类定义中,有4种常见的成员
类字段、类方法
实例字段、实例方法

5种常见的引用类型: class, interface, array, enumerated, annotation

public class Integer extends Number implements Serializable, Comparable {
    // class members go here
}

abstract class 抽象类,

无法被实例化
任何包含一个抽象方法的类都必须是抽象类

final class
该类无法被继承(扩展)
一个类无法同时声明为abstract 和 final

volatile表示类中字段,可能被多个线程同时调用,读取必须从主存到主存,不能从cpu缓存中读取

一般,类中static field都和final一起使用,用于定义常量

类字段:
可以当作全局变量
没有必要赋予初始化值,编译器将会给定初始值(如果没有初始值)

类方法:
可以看成是全局方法
可以使用同一个类中任意的类字段和类方法, 或者其他类中的类方法和类字段
无法使用类中的实例字段和实例方法

实例字段:
是面向对象编程的关键,保存着对象的状态信息,用于区别不同的对象
没有必要赋予初始化值,编译器将会给定初始值(如果没有初始值)

实例方法:
可以使用所有同一个对象实例的字段
可以使用类字段、类方法
对象可以看作是一组状态(通过实例字段)和在此状态下的一组行为(通过实例方法)的集合

this:
通常情况下,不需要显示声明this(当引用对象实例中的成员)
当本地变量或者实例方法中的变量名称和类字段相同时候,需要使用this

类构造函数:
任意类都至少有一个构造函数,用于创建对象后,进行对象初始化
如果源码中没有定义构造函数,javac编译器将创建一个默认的构造函数(没有传参,也没有特殊初始化)

有关名称、声明、编写构造函数:

  1. 名称总是和类名称相同;
  2. 声明中没有返回值类型
  3. 内部为初始化对象实例代码,相当于构造this引用的属性
  4. 没有返回值

定义多个构造函数类似于重载方法
构造函数中可以使用this, 调用该类中的其他构造函数

类字段初始化 vs 实例字段初始化

  1. 类字段初始化

javac编译器自动生成一个类初始化方法
类字段将在该初始化方法中真正初始化
通常在类首次调用之前(类第一次加载到jvm中),调用类初始化方法
也可以自定义一些类初始化块,它们将会合并到类初始化方法中(自动生成)

// We can draw the outline of a circle using trigonometric functions
// Trigonometry is slow, though, so we precompute a bunch of values
public class TrigCircle {
  // Here are our static lookup tables and their own initializers
  private static final int NUMPTS = 500;
  private static double sines[] = new double[NUMPTS];
  private static double cosines[] = new double[NUMPTS];

  // Here's a static initializer that fills in the arrays
  static {
    double x = 0.0;
    double delta_x = (Circle.PI/2)/(NUMPTS-1);
    for(int i = 0, x = 0.0; i < NUMPTS; i++, x += delta_x) {
      sines[i] = Math.sin(x);
      cosines[i] = Math.cos(x);
    }
  }
  // The rest of the class is omitted...
}
  1. 实例字段初始化

java编译器将自动生成字段的初始化代码,并且将之加入构造函数中
按照实例字段出现的顺序先后,将实例字段添加到构造函数中
如果构造函数1通过this调用构造函数2, 构造函数2中才会实际处理初始化字段

public class SampleClass {
  public int len = 10;
  public int[] table = new int[len];

  public SampleClass() {
    for(int i = 0; i < len; i++) table[i] = i;
  }

  // The rest of the class is omitted...
}
public SampleClass() {
  len = 10;
  table = new int[len];
  for(int i = 0; i < len; i++) table[i] = i;
}

子类和继承:

通过关键字extends实现继承

public class PlaneCircle extends Circle {
  // We automatically inherit the fields and methods of Circle,
  // so we only have to put the new stuff here.
  // New instance fields that store the center point of the circle
  private final double cx, cy;

  // A new constructor to initialize the new fields
  // It uses a special syntax to invoke the Circle() constructor
  public PlaneCircle(double r, double x, double y) {
    super(r);       // Invoke the constructor of the superclass, Circle()
    this.cx = x;    // Initialize the instance field cx
    this.cy = y;    // Initialize the instance field cy
  }

  public double getCentreX() {
    return cx;
  }

  public double getCentreY() {
    return cy;
  }

  // The area() and circumference() methods are inherited from Circle
  // A new instance method that checks whether a point is inside the circle
  // Note that it uses the inherited instance field r
  public boolean isInside(double x, double y) {
    double dx = x - cx, dy = y - cy;             // Distance from center
    double distance = Math.sqrt(dx*dx + dy*dy);  // Pythagorean theorem
    return (distance < r);                       // Returns true or false
  }
}

final 类:
类描述符final表示该类无法被继承, 例如:java.lang.String

父类,object类,类结构:

  1. 一个类只能有一个直接父类
  2. 每一个自定义的类都有一个父类,如果类没有被extends显示声明,其父类为java.lang.Object
  3. object类是java中唯一没有父类的类
  4. 其他所有类都继承自object类(直接或者间接)

clipboard.png

子类构造函数:

  1. 想要调用父类的构造函数,调用super()函数
  2. 只能在构造函数中调用super()
  3. 子类构造函数中,需要先调用super(), 然后再声明本地变量

构造函数链和默认构造函数:

  1. 每次创建新的对象实例时候,都会调用构造函数;
  2. 每次子类创建新的对象实例时候,都会调用父类的构造函数;
  3. 如果子类的构造函数没有this()或者super()调用父类的构造函数,javac编译器将会隐性添加super()没有参数的父类构造函数
  4. 若子类调用的父类构造函数没有显示声明,则会产生编译错误
  5. 类无法被实例化,如果类中定义了私有构造函数

隐藏父类字段

  1. 如果子类中有父类同名的字段,父类的同名字段被隐藏;所以,尽量不使用同名的字段;
  2. 隐藏父类字段不仅是实例字段,还有类字段

隐藏父类方法

  1. 当子类定义了一个实例方法,该方法和父类的实例方法有相同的名称、返回类型、传参列表,则父类中的实例方法将会被隐藏
  2. 实例方法隐藏
public class Car {
    public static final double LITRE_PER_100KM = 8.9;

    protected double topSpeed;

    protected double fuelTankCapacity;

    private int doors;

    public Car(double topSpeed, double fuelTankCapacity, int doors) {
        this.topSpeed = topSpeed;
        this.fuelTankCapacity = fuelTankCapacity;
        this.doors = doors;
    }

    public double getTopSpeed() {
        return topSpeed;
    }

    public int getDoors() {
        return doors;
    }

    public double getFuelTankCapacity() {
        return fuelTankCapacity;
    }

    public double range() {
        return 100 * fuelTankCapacity / LITRE_PER_100KM;
    }
}
public class SportsCar extends Car {

    private double efficiency;

    public SportsCar(double topSpeed) {
        super(topSpeed, 50.0, 2);
        if (topSpeed > 200.0) {
            efficiency = 200.0 / topSpeed;
        } else {
            efficiency = 1.0;
        }
    }

    public double getEfficiency() {
        return efficiency;
    }

    @Override
    public double range() {
        return 100 * fuelTankCapacity * efficiency / LITRE_PER_100KM;
    }

}

3.上面的是对象实例方法的负载,类方法有不同的表现,类方法无法被覆盖,但是可以被隐藏

重写不是隐藏:

class A {                          // Define a class named A
  int i = 1;                       // An instance field
  int f() { return i; }            // An instance method
  static char g() { return 'A'; }  // A class method
}

class B extends A {                // Define a subclass of A
  int i = 2;                       // Hides field i in class A
  int f() { return -i; }           // Overrides method f in class A
  static char g() { return 'B'; }  // Hides class method g() in class A
}

public class OverrideTest {
  public static void main(String args[]) {
    B b = new B();               // Creates a new object of type B
    System.out.println(b.i);     // Refers to B.i; prints 2
    System.out.println(b.f());   // Refers to B.f(); prints -2
    System.out.println(b.g());   // Refers to B.g(); prints B
    System.out.println(B.g());   // A better way to invoke B.g()

    A a = (A) b;                 // Casts b to an instance of class A
    System.out.println(a.i);     // Now refers to A.i; prints 1
    System.out.println(a.f());   // Still refers to B.f(); prints -2
    System.out.println(a.g());   // Refers to A.g(); prints A
    System.out.println(A.g());   // A better way to invoke A.g()
  }
}

查找虚拟方法:

  1. 假设,Car[]中包含了Car类和其子类SportsCar对象实例,javac编译器在编译时候,无法知道调用的实例方法range()该使用Car类的实例方法还是SportsCar的实例方法;
  2. javac编译器创建字节码,使用虚拟函数寻找在运行时候,当解释器运行字节码时候,解释器将获取适当的range()实例方法,相对于每一个Car[]中的实例对象
  3. C++等语言中,没有虚拟函数寻找机制,它们的替代方案是使用virtual关键字,如果子类被允许重写实例方法,则需要显示声明virtual

调用一个重写方法

class A {
  int i = 1;            // An instance field hidden by subclass B
  int f() { return i; } // An instance method overridden by subclass B
}

class B extends A {
  int i;                    // This field hides i in A
  int f() {                 // This method overrides f() in A
    i = super.i + 1;        // It can retrieve A.i like this
    return super.f() + i;   // It can invoke A.f() like this
  }
}

一曲广陵散
76 声望23 粉丝

柴米油盐酱醋茶