封装是面向对象的三大特征之一(另外两个是继承和多态),它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
构造器最大的用处就是在创建对象时执行初始化。 注意:如果我们没有给Java类提供任何构造器,则系统会为了这个类提供一个无参数的构造器,这个构造器的执行体为空,不做任何事情。Java类中至少包含一个构造器。
同一个类中具有多个构造器,多个构造器的形参列表不同,即被称为构造器重载。
继承是面向对象的三大特征之一。Java中的继承具有单继承的特点,每个子类只有一个直接父类。
Java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类被称为父类,有的也称其为基类、超类。
子类包含与父类同名方法的现象被称为是方法重写,也被称为方法覆盖。
重载发生在同一个类的多个同名方法之间,而重写发生在子类和父类的同名方法之间。
如果需要在子类方法中调用父类被覆盖的实例方法,则可使用super限定来调用父类被覆盖的实例方法。 如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的实例变量,而不是该类自己定义的实例变量。
子类不会获得父类的构造器,但子类构造器里可以调用父类构造器的初始化代码。 在一个构造器中调用同一个类中另一个重载构造器使用this调用来完成,在子类构造器中调用父类构造器使用super调用来完成。
Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。
class BaseClass { public int book = 6; public void base() { System.out.println("父类中的普通方法"); } public void test() { System.out.println("父类的被覆盖的方法"); } } public class SubClass extends BaseClass{ public String book = "Java"; public void test() { System.out.println("子类的覆盖父类的方法"); } public void sub() { System.out.println("子类的普通方法"); } public static void main(String[] args) { //编译时类型和运行时类型不同,多态发生 BaseClass ploys = new SubClass(); //输出6 System.out.println(ploys.book); //调用从父类继承来的base方法 ploys.base(); //执行当前类的test方法 ploys.test(); //error //ploys.sub(); } } }当把一个子类对象直接赋给父类引用变量时,BaseClass ploys = new SubClass();当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征。这就可能出现:相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,,这就是多态。
父类的引用引向了自己的子类对象。 前提 必须是类与类之间有关系,要么继承,要么实现存在覆盖。 好处 提高了程序的扩展性。 弊端 只能使用父类的引用访问父类的成员。 注意 对象的实例变量不具备多态性。
instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口),它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,返回true,否则返回false。 注意 instanceof运算符前面的操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系。
继承严重的破坏了父类的封装性。 为了保证父类有良好的封装性,不会被子类随意改变,设计父类应当有如下规则:
尽量把父类的所有成员变量都设置成private访问类型,不要让子类直接访问父类的成员变量。不要让子类可以随意访问、修改父类的方法。例:父类中仅为辅助其他的工具方法,应该使用private访问控制符修饰,让子类无法访问该方法;如果父类中的方法需要被外部类调用,则必须有public修饰,但又不希望子类重写该方法,可以使用final修饰符来修饰该方法;如果希望父类的某个方法被子类重写,但不希望被其它类自由访问,则可以使用protected来修饰该方法。尽量不要在父类构造器中调用将要被子类重写的方法。