zoukankan      html  css  js  c++  java
  • 面向对象基础(Java)

    方法

    public、private

    • private 使用 method 来间接赋值
    • SetNum()
    • GetNum()
    • this.x = x;
    • 传入数组类型 (String[] names)

    • 方法可以让外部代码安全地访问实例字段
    • 方法是一组执行语句,并且可以执行任意逻辑
    • 方法内部遇到return返回
    • 外部代码通过public方法操作实例,内部代码通过调用private方法

    可变参数

    相当于数组类型

    class Group {
        private String[] names;
        public void setNames(String... names) {
            this.names = names;
        }
    }
    
    Group g = new Group();
    g.setNames("Xiao Ming", "Xiao Hong", "Xiao Jun"); // 传入3个String
    g.setNames("Xiao Ming", "Xiao Hong"); // 传入2个String
    g.setNames("Xiao Ming"); // 传入1个String
    g.setNames(); // 传入0个String
    

    如果把可变参数改为String[]类型,则传参的时候比较麻烦,需要自己构造String[]先。

    class Group {
        private String[] names;
    
        public void setNames(String[] names) {
            this.names = names;
        }
    }
    Group g = new Group();
    g.setNames(new String[] {"Xiao Ming", "Xiao Hong", "Xiao Jun"}); // 传入1个String[]
    

    构造方法

    • 没有构造方法时,编译器会自动生成一个默认构造方法,构造方法名称与类名一样。
    • 如果既要使用带参数的构造方法,又想保留不带参数的构造方法,那么只能把两个构造方法都定义出来
    public class Main {
        public static void main(String[] args) {
            Person p1 = new Person("Xiao Ming", 15); // 既可以调用带参数的构造方法
            Person p2 = new Person(); // 也可以调用无参数构造方法
        }
    }
    
    class Person {
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        public String getName() {
            return this.name;
        }
    
        public int getAge() {
            return this.age;
        }
    }
    
    • 其实也可以定义只有一个参数的构造方法,有点重载的感觉,即多构造方法

    方法重载

    在一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。

    class Hello {
        public void hello() {
            System.out.println("Hello, world!");
        }
    
        public void hello(String name) {
            System.out.println("Hello, " + name + "!");
        }
    
        public void hello(String name, int age) {
            if (age < 18) {
                System.out.println("Hi, " + name + "!");
            } else {
                System.out.println("Hello, " + name + "!");
            }
        }
    }
    

    继承

    继承是面向对象编程中非常强大的一种机制,它首先可以复用代码。子类自动获得了父类的所有字段,严禁定义与父类重名的字段。

    • Java使用extends关键字来实现继承
    • 超类、父类、基类是同一个,子类、扩展类是同一个
    • Java只允许一个class继承一个类,一个类只有一个父类
    • 子类无法访问父类的private或者private方法
    • 为了让子类可以访问,需要把private改为protected,一个protected字段和方法可以被子类和子类的子类访问
    • 子类引用父类的字段时,可以用super.()
    • 子类不会继承任何父类的构造方法
    class Student extends Person {
        protected int score;
    
        public Student(String name, int age, int score) {
            super(name, age);
            // 调用父类的构造方法Person(String, int)
            this.score = score;
        }
    }
    

    向上转型和向下转型

    • Student是从Person继承下来的,那么一个引用类型为Person的变量,能否只想Student类型的实例
    Person p = new Student(); 
    
    • 把一个子类类型变为父类类型的赋值,称为向上转型。
    • 向上转型实际上是把一个子类变为更抽象的父类,安全。
    • 向上转型时,父类指向子类引用对象会遗失除与父类对象共有的其他方法,也就是在转型过程中,子类的新有的方法都会遗失掉,在编译时,系统会提供找不到方法的错误。
    • 一个父类类型强制转型为子类类型,就是向下转型。
    • 向下转型,恢复了子类的成员变量以及方法。
    Person p1 = new Student(); // upcasting, ok
    Person p2 = new Person();
    Student s1 = (Student) p1; // ok
    Student s2 = (Student) p2; // runtime error! ClassCastException!
    

    多态

    • override和overload不同的地方。override是重载,如果方法类型和参数不一样就是overload
    public class Main {
        public static void main(String[] args) {
            Person p = new Student();
            p.run(); // 应该打印Person.run还是Student.run?
        }
    }
    
    class Person {
        public void run() {
            System.out.println("Person.run");
        }
    }
    
    class Student extends Person {
        @Override
        public void run() {
            System.out.println("Student.run");
        }
    }
    
    //打印的是Student.run
    
    • Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。即调用的是Student的run()方法
    • 多态指针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
    • 在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过super来调用
    • 继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override
    • 如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final。用final修饰的类不能被继承
    • 可以在构造方法中初始化final字段
    class Person {
        public final String name;
        public Person(String name) {
            this.name = name;
        }
    }
    

    这样name被赋值后就不能被修改。

    抽象类

    • 如果父类方法本身不需要实现任何功能,仅是定义方法签名,目的是让子类去覆写,这就是抽象方法
    • abstract class Person 抽象类
    • 抽象类不能被实例,Persion p = new Person()错误

    接口

    如果一个抽象类没有字段,所有方法全部是抽象方法,就可以把该抽象类改写为接口interface。

    • 在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。
    abstract class Person {
        public abstract void run();
        public abstract String getName();
    }
    
    interface Person {
        void run();
        String getName();
    }
    
    • 所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来(写不写效果都一样)。
    • 当一个具体的class去实现一个interface时,需要使用implements关键字
    class Student implements Person {
        private String name;
    
        public Student(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
            System.out.println(this.name + " run");
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    }
    
    

    implements用于接口。在Java中,一个类只能继承另一个类,不能从多个类继承。但是一个类可以实现多个interface。

    class Student implements Person, Hello { // 实现了两个interface
        ...
    }
    
    • 一个interface可以继承自另一个interface。interface继承自interface使用extends,它相当于扩展了接口的方法
    • 实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。

    静态字段和静态方法

    静态字段static field。静态字段只有一个共享空间,所有变量的静态字段共享一个空间。比如两个对象a,b a.x和b.x是一样的 假设x是static

    静态方法

    调用静态方法不需要实例变量,通过类名就可以调用。

    public class Main {
        public static void main(String[] args) {
            Person.setNumber(99);
            System.out.println(Person.number);
        }
    }
    
    class Person {
        public static int number;
    
        public static void setNumber(int value) {
            number = value;
        }
    }
    
    

    因为静态方法属于class而不属于实例,因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段。
    静态方法常用于工具类,例如Arrays.sort()和Math.random()

    接口的静态字段

    因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型

    public interface Person {
        public static final int MALE = 1;
        public static final int FEMALE = 2;
    }
    

    classpath和jar

    • classpath是JVM用到的一个环境变量,它用来指示JVM如何搜索class
    • jar包就是用来干这个事的,它可以把package组织的目录层级,以及各个目录下的所有文件(包括.class文件和其他文件)都打成一个jar文件,这样一来,无论是备份,还是发给客户,就简单多了。
    • jar包还可以包含一个特殊的/META-INF/MANIFEST.MF文件,MANIFEST.MF是纯文本,可以指定Main-Class和其它信息。JVM会自动读取这个MANIFEST.MF文件,如果存在Main-Class,我们就不必在命令行指定启动的类名,而是用更方便的命令

    模块

    • 如果漏写了某个运行时需要用到的jar,那么在运行期极有可能抛出ClassNotFoundException
    • 从Java 9开始引入的模块,主要是为了解决“依赖”这个问题。如果a.jar必须依赖另一个b.jar才能运行,那我们应该给a.jar加点说明啥的,让程序在编译和运行的时候能自动定位到b.jar,这种自带“依赖关系”的class容器就是模块。
    • 这些模块以.jmod扩展名标识,可以在$JAVA_HOME/jmods目录下找到它们
    • 模块之间的依赖关系已经被写入到模块内的module-info.class文件了。所有的模块都直接或间接地依赖java.base模块,只有java.base模块不依赖任何模块,它可以被看作是“根模块”,好比所有的类都是从Object直接或间接继承而来。
  • 相关阅读:
    干净卸载mysql (注册表)
    计算机中丢失 MSVCR100.dll
    ORM框架SQLAlchemy学习笔记
    mac sourcetree required password
    ConstantBuffer
    Unity通用渲染管线Shader日志输出工具
    Unity SRP Batcher的工作原理
    Unity中的深度测试相关知识与问题
    渲染杂谈:early-z、z-culling、hi-z、z-perpass到底是什么?
    Unity Compute Shader入门初探
  • 原文地址:https://www.cnblogs.com/chenshaowei/p/13175817.html
Copyright © 2011-2022 走看看