**
Java基础笔记—第五篇(继承、重写、多态、重载、final)
**
1. 继承
继承—对象的一个新类可以从现有的类中派生,这个过程称为类继承。继承其实是对类的重用,提供了一种明确表述共性的方法。(私有成员也可以继承,但由于访问权限的控制,在子类中不能直接使用父类的私有成员,可以通过从父类中继承得到protected、public方法,如getter、setter方法访问)Java是单继承,一个子类只能有一个父类。
- 当生成子类对象时,java默认先调用父类无参构造方法,然后执行该构造方法,生成父类对象;接下来调用子类的构造方法,生成子类的对象。
- 子类用super()显示调用父类的某个对应的构造方法,也必须放在第一条执行语句。当两个方法形成重写关系时,子类调用super.run()调用父类的run方法(不必放在第一条语句执行)。
2. 重写
重写其实就是方法的覆盖
- 子类覆盖方法和父类被覆盖方法返回类型、方法名称、参数列表必须相同;
- 子类覆盖方法的访问权限必须大于等于父类的访问权限;(public>protected>default>private)
- 方法覆盖只能存在于子类和父类之间;
- 子类覆盖方法不能比父类被覆盖方法跑出更多异常。(例:父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。)
3. 多态
多态(Polymorphism):父类型的引用可以指向子类的对象。在一个类中,可以定义多个同名的方法,只要确定它们的参数个数和类型不同,这种现象称为类的多态。类的多态性体现在两方面:一是方法的重载上,包括成员方法和构造方法的重载;二是在继承过程中,方法的重写。
Java实现多态有三个必要条件:继承、重写、向上转型。
public class Wine {
public void fun1(){
System.out.println("Wine的fun1.....");
fun2();
}
public void fun2(){
System.out.println("Wine的fun2...");
}
}
public class JNC extends Wine{
/**
* @desc 子类重载父类方法
* 父类中不存在该方法,向上转型后,父类是不能引用该方法的
* @param a
* @return void
*/
public void fun1(String a){
System.out.println("JNC的fun1...");
fun2();
}
/**
* 子类重写父类方法
* 指向子类的父类引用调用fun2时,必定是调用该方法
*/
public void fun2(){
System.out.println("JNC的fun2...");
}
}
public class Test {
public static void main(String[] args) {
Wine a = new JNC();
a.fun1();
}
}
-------------------------------------------------
输出:
Wine的fun1.....
JNC的fun2...
向上转型:指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1:" + a1.show(b));
System.out.println("2:" + a1.show(c));
System.out.println("3:" + a1.show(d));
System.out.println("4:" + a2.show(b));
System.out.println("5:" + a2.show(c));
System.out.println("6:" + a2.show(d));
System.out.println("7:" + b.show(b));
System.out.println("8:" + b.show(c));
System.out.println("9:" + b.show(d));
}
}
-------------------------------------------------
输出:
1:A and A
2:A and A
3:A and D
4:B and A
5:B and A
6:A and D
7:B and B
8:B and B
9:A and D
当父类对象引用变量引用子类对象时(A a2 = new B();
),被引用对象的类型不是引用变量的类型决定了调用谁的成员方法。被调用的方法必须是在父类中定义过的(public String show(A obj){}
),也就是说被子类覆盖的方法;没有被子类覆盖的的方法,父类特有的方法,调用执行父类的代码块(public String show(D obj){}
);子类特有的方法(public String show(B obj){}
),父类对象不可以调用;被子类覆盖过的方法,父类对象调用时,执行的是子类覆盖后的执行条件(return ("B and A");
)。
4. 重载
重载(Overloading):方法重载是让类以统一的方式处理不同类型数据的一种手段,多个同名函数同时存在,具有不同的参数个数/类型;Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义;重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同,无法以返回型别作为重载函数的区分标准。
重载规则:
- 必须具有不同的参数列表;
- 可以有不同的返回类型,只要参数列表不同就可以了;
- 可以有不同的访问修饰符;
- 可以抛出不同的异常;
5. final
- final修饰类:类不能被继承,final类中所有成员都会隐式地指定为final方法。
- final修饰方法:第一个是把方法锁定,以防任何继承类修改它的含义;第二个是效率,早期Java会将final转为内嵌调用,但如果方法过于庞大,就可能看不到内嵌调用带来的任何性能提升,最近版本中,不需要使用final优化啦。
- 父类的final方法是不能被子类覆盖的,也就是说子类是不能够存在和父类一模一样的方法的,不能被重写(可以重载多个final修饰的方法);如果父类中final修饰的方法同时访问权限为private,将会导致子类中不能直接继承到此方法,此时,就可以在子类中定义相同方法名和参数的方法,不再产生重写与final的矛盾,而是在子类中定义了新的方法。(类的private方法会隐式地被指定为final方法)。
- final修饰变量: final修饰一个成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦初始化后便不能发生变化;
- 当final修饰一个引用类型时,则在对其初始化之后便不能在让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的;
- 当函数的参数类型声明为final时,说明该参数只读,即可以读取,但不可以修改。
public class Test {
public static void main(String args[]){
String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b+2;
String e = d+2;
System.out.println((a == c));
System.out.println((a == e));
}
}
-------------------------------------------------
输出:
true
false
当final变量是基本数据类型或String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译器常量使用。
public class Test {
public static void main(String args[]){
String a = "hello2";
final String b = getHello();
String c = b+2;
System.out.println((a == c));
}
public static String getHello(){
return "hello";
}
}
-------------------------------------------------
输出:
false
- final参数:
public class TestFinalParam{
public static void main(String args[]){
TestFinalParam testFinalParam = new TestFinalParam();
StringBuffer buffer = new StringBuffer("hello");
testFinalParam.changeValue(buffer);
System.out.println(buffer);
}
public void changeValue(final StringBuffer buffer){
//buffer重新指向另一个对象,final修饰引用类型的参数时,不能让其再指向其他对象,但是对其指向的内容可以修改
buffer = new StringBuffer("hi"); //如果参数中有final关键字,这里会报错,如果没有正常执行
buffer.append("world");
System.out.println(buffer);
}
}
-------------------------------------------------
若参数中有final关键字输出:
报错
若参数中没有final关键字输出:
hiworld
helloworld