面向对象编程

类声明

// 声明Person类
class Person {
    // 声明成员属性
    private String name;
    private int age;

    // 声明构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 默认构造方法
    public Person() {}

    public String getName() {
        return this.name;
    }

    public void setName(String name){
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    // 方法重载(即只要参数不同,允许同名方法)
    public void greet() {
        System.out.println("Hello, world!");
    }

    public void greet(String name) {
        System.out.println("Hello, " + name + "!");
}

public class Main {
    public static void main(String[] args) {
        // 实例化Person类
        Person p1 = new Person(); 
        Person p2 = new Person("zhangsan",19); 
    }
}

Java中的类声明与Dart中的很相似,主要有以下几点需注意

  • Java使用private关键字修饰类的私有成员,Dart中则以_开头的方式私有化。但对于暴露给外部访问的方法或属性,则必须使用public关键字修饰
  • Java存在方法重载机制,只要参数不同,方法名可以相同。因此Java中的类可以定义许多同名的构造方法,但没有命名构造方法。
  • Java中创建类的实例对象必须使用new关键字,不能省略
  • Java没有setget关键字实现setter和getter机制,setter和getter只是普通的方法。
  • Java类中的成员属性有默认值,引用类型的属性默认null,其他基础数据类型中数值类型默认值是0,布尔类型默认值是false

继承

// 使用extends关键字从Person类继承,可以复用代码,只需要声明自己特有的属性
class Student extends Person {

    private int score;

    public Student(String name, int age, int score) {
        super(name, age); // 使用super调用父类的构造方法
        this.score = score;
    }

    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
}

Java中亦使用extends关键字来实现继承,但也有一些需要注意的地方:

  • Java只能单继承,没有类似Dart里面的mixin混入机制。因此,一个类有且仅有一个父类

  • 与Dart一样,Object类是所有类的超类

  • 子类不能访问父类中使用private关键字修饰的属性和方法。如果父类希望被子类访问,一般使用protected关键字修饰

  • 子类中实现父类中的同名方法称为覆写,注意方法重载与方法覆写的区别。方法重载要求两个方法的方法签名不能相同;而覆写要求两个方法的方法签名必须相同,它们唯一相似的地方只是两者都要求这两个方法的方法名相同。

  • 如果一个父类不允许子类对它的某个方法进行覆写,但允许调用,这时可以使用final修饰该方法

  • 如果一个类不希望被其他类继承,那么也可以在声明时用final修饰,被final修饰的类不能被继承,例如:

    final class Person {...}

多态

多态指针对某个类型的方法调用,其实际执行方法的取决于运行时期实际类型。表现到代码中,就是在实例化对象时,使用父类指向子类

public class Main {
    public static void main(String[] args) {
        // 让父类指向子类
        Person p = new Student("zhangsan",19,99); 
    }
}

抽象类

Java中的抽象类与Dart类似。抽象类强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法就相当于一种“规范”,抽象类统一定义这种“规范”,由子类具体实现这些“规范”。所以抽象类不能直接实例化,必须由子类实例化,可以利用多态,实例化时让父类指向这个具体实现的子类。

// 声明一个抽象类,包含一个抽象方法
abstract class Person {
    public abstract void greet();

    // 抽象类中也可以声明非抽象方法
    public String getName() {
        return "";
    }
}

class Student extends Person {

    // 子类覆写抽象方法
    @Override
    public void greet() {
        System.out.println("hello");
    }
}

public class Main {
    public static void main(String[] args) {
        // 父类执行子类
        Person p = new Student();
        p.greet();
    }
}
  • Java中,抽象类的抽象方法必须使用abstract关键字声明,Dart中省略方法体即表示抽象方法。
  • 抽象类中也可以定义非抽象方法
  • 普通类中也可以定义抽象方法,一旦定义抽象方法,则其子类必须强制实现该方法

接口

实际上接口和抽象类的作用是相似的,如果一个抽象类中的全部方法都是抽象方法,那么这个抽象类就相当于接口。但是,由于Java只能单继承,不能多继承,因此抽象类就有了局限,很多时候,可能需要继承多个类,于是就有了接口。Java中的类可以实现多个接口。

// 声明一个接口
interface Person {
    // 定义方法签名,不能有方法体
    void greet();
    String getName();
}

注意,一般接口都写到一个单独的源码文件中

// 一个类实现一个接口
class Student implements Person {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void greet() {
        System.out.println("hello");
    }

    @Override
    public String getName() {
        return this.name;
    }
}

public class Main {
    public static void main(String[] args) {
        // 接口指向具体实现类,多态
        Person p = new Student("zhangsan");
        p.greet();
    }
}
  • 注意早期Java接口中只能定义方法签名,不能有方法实现

  • Java的接口之间是可以继承的,并且可以多继承

    public interface A {
        void a();
    }
    
    public interface B {
        void b();
    }
    
    // 一个接口可以继承多个接口
    public interface Test extends A,B {
        void c();
    }
    
  • Java 8新特性,接口中可以添加使用default或者static修饰的方法

内部类和匿名内部类

将一个类声明到另一个类的内部(嵌套声明),那么这个类就是内部类。对于内部类,需要注意,内部类可以调用外部类中的属性和方法,反过来,外部类不能调用内部类中的属性和方法。Dart语言中是没有内部类的。

// 外部类
class Outer{
    private String str ="外部类成员属性";

    //声明一个内部类
    class Inner{
        private String inStr= "内部类成员属性";

        public void print(){
            //访问外部类的属性
            System.out.println(str);
        }
    }

    public void func(){
        //创建内部类对象
        Inner in = new Inner();
        in.print();
    }
}


public class Test{
    public static void main(String[] args){
        // 实例化外部类对象
        Outer out = new Outer();
        out.func();

        // 在外部实例化一个非静态内部类,必须先实例化这个内部类的外部类
        Outer.Inner in = new Outer().new Inner();
    }
}

匿名内部类是一个没有名字的在方法中声明的内部类。Java中没有闭包,这种匿名内部类写法,相当于的Dart中的闭包。

interface Work{
    void run();
}

abstract class Human{
    public abstract void eat();
}

public class Test{
    public static void main(String[] args){
        // 创建一个匿名内部类,实现run方法,并实例化,同时调用run方法
        new Work(){
            public void run(){
                System.out.println("run");
            }
        }.run();


        new Human(){
            public void eat(){
                System.out.println("eat");
            }
        }.eat();
    }
}

需要特别注意:

  • 匿名内部类必须继承一个类或者实现一个接口
  • 匿名内部类没有类名,因此没有构造方法
  • 匿名内部类访问局部变量时,局部变量必须使用final修饰(JDK 8之前)

静态成员和静态方法

类中声明的普通属性,称为成员属性或成员变量;而使用static修饰的成员则称为静态成员。普通成员变量在每个实例对象中都有自己的一个独立“空间”,但静态成员只有一个共享“空间”,类的所有实例对象都会共享该成员变量。因此我们可以直接通过类名去访问静态成员变量,而不需要先实例化该类。

class Person {
    public static int number = 18;

    public static void setNumber(int value) {
        number = value;
    }
}

public class Main {
    public static void main(String[] args) {
        // 类名直接访问
        System.out.println(Person.number);
        Person.setNumber(20);
    }
}

类中使用static修饰的方法称为静态方法。同理,静态方法通过类名直接调用,无需实例化。

需要注意:静态方法中,只能访问static修饰的静态成员,不能访问非静态成员。

static拓展:静态代码块

 class Hello {

    // 静态代码块:独立于类成员的static语句块,不在任何的方法体内
    // 在字节码被加载时执行,只会执行一次,因此优先于类的构造方法执行。
    static {
        System.out.println("Static code block");
    }
}

Java中将一种名字空间,称之为包:package。一个类总是属于某个包,类名(比如Person)只是一个简写,真正的完整类名应是包名.类名

包名,其实就是源码所在文件夹的路径(src作为源码根目录,包名从src之后开始),同一个包之内的范围,称为包作用域。我们使用import导入相关包下面的类。

什么是jar包?

我们知道源码需要编译成.class文件,这些字节码文件散落在各级目录中,不便管理,这时就需要把那些目录打成一个包方便管理。jar包实际上就是一个zip压缩文件而已,我们可以手动用zip压缩目录,然后将压缩包后缀名改为.jar,这样就手动生成了一个jar包,但是不建议手动去做这种事,因为jar包中通常还需要一个配置文件MANIFEST.MF来描述main函数入口。

访问控制

在Java中共有四种访问控制,即publicprotectedprivate和缺省,使用这些修饰符可以限制访问作用域。

类型转换

当两个类型可以强制类型转换时,可以用括号的方式强转,否则就会报错

public class Main {
    public static void main(String[] args) {
        Person p = new Student("zhangsan",19,99);
        // 强制类型转换
        Student stu = (Student)p;
    }
}

包装类

Java是一门面向对象的编程语言,然而却存在8种基本数据类型,这些基本数据类型显然不是面向对象的,在使用泛型之类的特性时,就存在缺陷,为了解决这个问题,Java在1.5版本时,提出了包装类的概念。

所谓包装类,就是将八种基本数据类型转化为对象类型。显然的,Dart语言在设计时就避免了这种问题,因此Dart中没有基本数据类型,即使是数值,也是用对象类型来表示。

需要注意,包装类是一个类,所以是引用数据类型,它的零值是null

    // 基本数据类型转包装类型
    Integer num = new Integer(18);
    Double pi = new Double(3.14);

    // 包装类型转基本数据类型
    int n = num.intValue();
    double p = pi.doubleValue();

    // 还可直接隐式转换
    int l = num;
    double q = pi;

枚举

Java中的枚举与Dart中有些相似,也可用于switch条件分支中

// 声明一个颜色枚举
enum Color { RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE }

enum Week { Mon, Tue, Wed, Thu, Fri, Sat, Sun }

公众号“编程之路从0到1”

20190301102949549

Copyright © Arcticfox 2021 all right reserved,powered by Gitbook文档修订于: 2022-05-01 12:20:20

results matching ""

    No results matching ""