javaSE 面向对象高级
作者:gqk:
本章内容:
1、 继承的基本概念及实现、继承的各个使用限制
2、 子类对象的实例化过程
3、 方法的覆写
4、 super 和 this关键字的作用
5、 final 关键字的作用
6、 抽象类和接口的基本概念
8、 对象多态性
为什么要使用继承
当我们发现一个类的功能不行,方法不够用时,就可以派生子类,增加方法。
当我们需要定义一个能实现某项特殊功能的类时,就可以使用继承。
最终还是为了一个目的,实现代码的复用性。
继承关系的引出:
从以上的代码很明显的可以发现,有大量的重复代码出现,而且通过实际的问题可以发现,学生本身就是一个人。
面向对象开发的目的就是为了消除掉重复的代码,但是按照之前的编写套路很明显,已经不能满足于这种现实问题, 所以下面就需要采用继承的形式,语法如下:
class 子类 extends 父类{}
现在的 Student 类继承了 Person 类之后,发现可以将 Person 类中定义的方法任意的使用,子类也允许对父类中的定 义进行扩充:(在子类中添加school属性和方法)
继承的限制
1,子类可以继承父类的全部操作(属性、方法),但是对于所有的公共操作是可以直接继承的,而所有的私有操作是无 法直接进程的,而是通过其他的方式间接访问。
2,一个子类只能继承一个父类,属于单继承,而不能同时继承多个父类
3、 在 Java 中允许多层继承。
class A { }; class B extends A { }; class C extends B { };
子类对象的实例化 (试试下面代码)
package demo; public class Student extends supercls { private String name; private int age; private String school; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } }; class supercls{ private String name; private int age; public supercls(String name, int age) { super(); this.name = name; this.age = age; } }
原因:此时提示的是没有找到 supercls类的无参构造方法,现在是子类出现的错误,因为一个类中一旦构造方法被调用之后, 实际上就意味着此类可以使用了,对象已经产生了,就好比一个人一样已经出生了。 所以按照正常的思维来讲,肯定是先有父类产生再有子类产生,所以在子类对象实例化的时候实际上都会默认去调 用父类中的无参构造方法
演示Super的用法,调用父类中的方法:
覆写(重点)
继承本身可以进行类的功能扩充,但是扩充之后也会存在问题,例如:在子类中定义了和父类完全一样的方法或者 是定义了一样的属性,那么此时实际上就发生了覆写操作。
所谓方法的覆写就是指一个子类中定义了一个与父类完全一样的方法名称,包括返回值类型、参数的类型及个数都 是完全一样的,但是需要注意的是,被覆写的方法不能拥有比父类更严格的访问控制权限。
class A { public void print(){ // 定义方法 System.out.println("hello") ; } }; class B extends A { public void print(){ System.out.println("world") ; }
}; public class OverrideDemo01 { public static void main(String args[]){ B b = new B() ; b.print() ; //此时执行的是子类复写过的方法 } };
在子类中一旦方法被覆写之后,实际上最终调用的方法就是被覆写过的方法,但是,如果此时在子类中的方法的访 问权限已经降低的话,则编译的时候将出现错误
一定要记住,方法名称、返回值、参数列表完全一样就称为覆写。(发生在继承之中)
两个重要概念(重点)
重载及覆写的区别:
this 与 super 的区别
思考题:
定义一个银行卡的父类,有属性 账号,余额,取钱,各个分行也可以取钱,完成各个分行取钱并显示余额;跨行取钱有手续费
final 关键字(重点)
在 Java 中可以使用 final 关键字定义类、方法、属性:
使 用 final 关键字定义的类不能有子类(final修饰的类不能被继承)
使 用 final 声明的方法不能被子类所覆写 ·
使 用 final 声明的变量即成为常量,常量必须在声明时给出具体的内容。
单例设计:重要的设计模式之一,只产生一个对象
//懒汉式
package demo; public class Test{ public static void main(String[] args) { Singleton s1 = Singleton.getInstance() ; Singleton s2 = Singleton.getInstance() ; Singleton s3 = Singleton.getInstance() ; System.out.println(s1); System.out.println(s2); System.out.println(s3); } } class Singleton{ private final static Singleton instance = new Singleton() ; // 在内部准备好一个对象 private Singleton(){ } public static Singleton getInstance(){ return instance; } public void println(){ System.out.println("helloworld"); } }
此时,不管外部如何变化,Singleton 类中永远只会有一个实例化对象,此种代码实现的根本原理就是在于将一个类 的构造方法关闭了。
当一个类中只能产生一个实例化对象的时候,就需要将构造方法封闭,封闭之后的操作通过一个静态方法取得本类 的实例化对象,这种代码的概念非常重要,而且代码的结构必须清楚。 编写 Singleton 类的话,就按照此种代码完整写出即可。 如果要想继续划分的,实际上单例设计,还分成两种类型:
懒汉式:当第一次使用本类的对象时,在进行对象的实例化操作。(在第一次创建对象的时候)
饿汉式:一个单例类中不管是否使用,都始终维护一个实例化对象。(在类加载的时候)
//饿汉式
package demo; public class Test{ public static void main(String[] args) { Singleton s1 = Singleton.getInstance() ; Singleton s2 = Singleton.getInstance() ; Singleton s3 = Singleton.getInstance() ; System.out.println(s1); System.out.println(s2); System.out.println(s3); } } class Singleton{ private static Singleton instance = null ; // 在内部准备好一个对象 private Singleton(){ System.out.println("111111"); } static{ instance = new Singleton(); } public static Singleton getInstance(){ if(instance==null){ instance = new Singleton(); } return instance; } public void println(){ System.out.println("helloworld"); } }
抽象类:
抽象类的定义比较简单,包含一个抽象方法的类就是抽象类,抽象类必须使用 abstract 关键字进行声明。
抽象方法:只声明而未定义方法体的方法称为抽象方法,抽象方法也必须使用 abstract 关键字声明。
抽 象类不能直接实例化。
抽 象类必须有子类,子类(如果不是抽象类)的话,则必须覆写抽象类中的全部抽象方法。
如果一个抽象类中没有任何一个抽象方法,依然是抽象类。
问题
1,抽 象类能使用 final 声明吗? ·
不能:final 声明的类不能被继承,而抽象类又必须要有子类。
2,抽 象类中能有构造方法吗? ·
可以存在,而且依然符合于子类对象的实例化过程的要求。
接口(重点)
当一个类中全部是由抽象方法和全局常量组成的时候,那么就可以将这个类定义成一个接口了,接口使用 interface 关键字声明
一个接口定义完成之后,实际上与抽象类的使用原则是一样的:
1,接口必须有子类,子类(如果不是抽象类)则必须覆写接口中的全部抽象方法;
2,接口是不能直接进行对象的实例化操作。
3, 一个子类可以同时继承(实现)多个接口,如下所示:
class 子类 implements 接口 A,接口 B,…{}
对象多态性(重点)
方法的重载及覆写
对象多态性:指的是父类对象和子类对象之间的转型操作
向上转型(子类 父类): 父 类名称 父类对象 = 子类实例 ; 自动完成
向下 转 型 ( 父 类子 类): 子 类名称 子类对象 = (子类名称)父类实例 ; 强制完成
stanceof 关键字(重点)
通过 instanceof 关键字可以判断某一个对象是否是某一个类的实例。(出现在继承或者接口的实现之中)
Object(重点)
Object 类是所有类的父类,如果一个类定义的时候没有明确的继承一个类的话,则默认继承 Object 类。
对象比较:equals();
package demo; public class Person { private String name; private int age; private static String str1 = "hello"; private static String str2 = "hello"; public Person(String name, int age) { this.name = name; this.age = age; } public boolean equals(Object obj){ Person per = null; if(this==obj){ return true; } if(obj instanceof Person){ per = (Person) obj; return true; } if(this.name.equals(per.name) && this.age==per.age){ return true; }else{ return false; } } public static void main(String[] args) { Person p1 = new Person("admin", 18); Person p2 = new Person("admin", 18); System.out.println(p1==p2); System.out.println(p1.equals(p2)); System.out.println(str1.equals(str2)); } }
总结:
1、 继承可以用来扩充已有类的功能,使用 extends 关键字,在 Java 中只允许单继承而不允许多继承,而且继承时实际上 是将所有的内容都继承了下来,只是有些内容是显式继承,私有的属于隐式继承。
2、 子类对象的实例化:子类对象实例化之前先去调用父类的构造方法,之后再调用子类的构造方法。
3、 this和 super 的区别;重载及覆写的区别。
4、 覆写:子类定义了一个与父类完全一样的方法,称为覆写,覆写的时候必须注意访问控制权限。
5、 final 关键字:定义的类不能被继承、定义的方法不能被覆写、定义的变量就是常量。
6、 抽象类:包含一个抽象方法的类称为抽象类,抽象类必须有子类,子类要覆写全部的抽象方法。
7、 接口:由抽象方法和全局常量组成的特殊类,一个类可以实现多个接口,接口可以实现多继承。
8、 对象多态性及 instanceof 关键字
9、 Object 类:所有类的父类