1 继承的概述先观察如下代码
package java007;/** * 2017/9/9 * 说明:学生 */public class Student { String name; int age; public void study(){ System.out.print("我叫"+name+",今年"+age+",我是一名学生,正在学习"); }}
package java007;/** * 2017/9/9 * 说明:工人 */public class Worker { String name; int age; public void work(){ System.out.print("我叫"+name+",今年"+age+",我是一名工人,正在工作"); }}
package java007;/** * 2017/9/9 * 说明: */public class StudentAndWorkderTest { public static void main(String[] args) { Student s = new Student(); s.name = "张三"; s.age = 15; s.study(); Worker w = new Worker(); w.name = "李四"; w.age = 34; w.work(); }}
我们可以发现学生类和工人类中都有姓名和年龄属性,属于重复字段,那么如何解决?,且看如下代码。
package java007;/** * 2017/9/9 * 说明: */public class Person { String name; int age;}
package java007;/** * 2017/9/9 * 说明:学生 */public class Student extends Person { public void study(){ System.out.print("我叫"+name+",今年"+age+",我是一名学生,正在学习"); }}
package java007;/** * 2017/9/9 * 说明:工人 */public class Worker extends Person{ public void work(){ System.out.print("我叫"+name+",今年"+age+",我是一名工人,正在工作"); }}
package java007;/** * 2017/9/9 * 说明: */public class StudentAndWorkderTest { public static void main(String[] args) { Student s = new Student(); s.name = "张三"; s.age = 15; s.study(); Worker w = new Worker(); w.name = "李四"; w.age = 34; w.work(); }}
继承的好处:①提高了代码的复用性。②让类与类之间产生关系,给第三个特征多态提供了前提。
2 继承的特点Java中支持单继承(一个子类只能有一个父类),不直接直接多继承,支持多层继承。
3 super关键字当本类的成员变量和局部变量同名的时候,使用this区分。当子父类的成员变量同名的时候,使用super区分父类。this和super的用法很相似。
示例1:本类的成员变量和局部变量同名的时候
package java007;/** * 2017/9/9 * 说明: */class Fu{ private int age = 20; public void show(){ int age = 10; System.out.print("局部变量:"+age+",成员变量:"+this.age); }}public class ExtendsDemo { public static void main(String[] args) { Fu f = new Fu(); f.show(); }}
解释说明:①先使用javac ExtendsDemo.java命令将ExtendsDemo编译成class文件,当然,顺便将Fu.java也编译成class文件。②使用java ExtendsDemo命令,虚拟机会从方法区中,将main()方法识别,并加载到栈中。③执行了new Fu();会在堆内存中开辟一个空间,(将Fu(){}加载到栈内存中,因为这一部分对本程序而言不是很重要,所以省略相关描述),用来存储对象,并初始化age=0。然后执行到private int age = 20;的时候,就将20赋值给age,此时age在堆内存中是20。④Fu f = new Fu();main()方法所在的栈内存中,开辟了一个引用变量f,然后将堆内存中的对象的地址赋值给f,那么此时f就指向堆内存中的对象。⑤f.show();从方法区将show()方法加载到栈中,此时,注意的是,show()方法内部就包含了this关键字,同时f变量的地址值给了this,因为this表示的是当前对象的引用,而调用show()方法的恰恰是f,所有this和f此时的值是相同的,那么show()方法也指向了堆内存中的对象,然后在show()方法内部开辟了一个age变量,这个age变量是栈内存中show()方法内部的局部变量,而想获取堆内存中的age变量,只能通过show()方法内存的this关键字了。
示例2:子类和父类的成员变量不同的时候
package java007;/** * 2017/9/9 * 说明: */class Fu{ int age1 = 20;}class Zi extends Fu{ int age2 = 30; public void show(){ System.out.print(age1+" "+age2); }}public class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); }}
解释说明:通过上面的程序貌似可以这样解释,第一,变量名是不一样的,第二,子类是继承了父类,而子类中没有age1成员变量,所以从父类中继承(拷贝)了age1成员变量。
示例3:子父类的成员变量相同的时候
package java007;/** * 2017/9/9 * 说明: */class Fu{ int age = 20;}class Zi extends Fu{ int age = 30; public void show(){ System.out.print(age); }}public class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); }}
package java007;/** * 2017/9/9 * 说明: */class Fu{ int age = 20;}class Zi extends Fu{ int age = 30; public void show(){ System.out.print(age+" "+super.age); }}public class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); }}
解释说明:通过上面的程序貌似可以这样解释,子类和父类成员变量相同的时候,子类可以将父类相同成员变量覆盖,其实不然,且看下面分解。
4 函数覆盖(重写)示例:子父类中的方法名不同
package java007;/** * 2017/9/10 * 说明: */class Fu{ public void show1(){ System.out.print("Fu的show1方法"); }}class Zi extends Fu{ public void show2(){ System.out.print("Zi的show2方法"); }}public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); z.show1(); z.show2(); }}
示例:子父类中的方法名同名
package java007;/** * 2017/9/10 * 说明: */class Fu{ public void show(){ System.out.print("Fu的show方法"); }}class Zi extends Fu{ public void show(){ System.out.print("Zi的show方法"); }}public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); z.show(); }}
当子类中出现成员函数和父类的一样的时候,会运行子类的成员函数,从表现上看。好像是子类的成员函数“覆盖”了父类的成员函数,这种现象,被称为重写或者覆盖。函数的两个特性:重载。同一个类中。覆盖。子类中,也称为重写。 重写的注意事项:子类方法覆盖父类方法时,子类方法的权限必须>=父类方法的权限。
5 子类的实例化过程示例:
package java007;/** * 2017/9/10 * 说明: */class Fu{ public Fu(){ System.out.println("Fu的构造方法"); }}class Zi extends Fu{ public Zi(){ System.out.println("Zi的构造方法"); }}public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); }}
在子类构造对象的时候,发现,访问子类构造函数的时候,父类也运行了。这是为什么?因为,在子类构造方法中的第一行有一个默认的隐式语句:super();j如下代码所示。
package java007;/** * 2017/9/10 * 说明: */class Fu{ public Fu(){ System.out.println("Fu的构造方法"); }}class Zi extends Fu{ public Zi(){ super();//调用的是父类的默认的空参数构造函数 System.out.println("Zi的构造方法"); }}public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); }}
示例:
package java007;/** * 2017/9/10 * 说明: */class Fu{ public Fu(){ show(); } public void show(){ System.out.print("fu show"); }}class Zi extends Fu{ int num = 8; public Zi(){ } public void show(){ System.out.print("zi show:"+num); }}public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); z.show(); }}
解释:先将父类进行初始化,再将子类进行初始化。
6 final关键字final可以修饰类、方法和变量。final修饰的类不可以被继承。final修饰的方法不可以被重写。final修饰的变量是一个常量,只能被赋值一次。内部类只能访问被final修饰的局部变量。
示例:final修饰变量,变为常量
class Person{ private final int age = 10;}
示例:final修饰变量,变为常量
class Person{ private final int age ; { age = 20; }}
示例:final修饰变量,变为常量
class Person{ private final int age ; public Person(int age){ this.age = age; }}
最糟糕的行为是抱怨,最易见效 的努力是从自己做起。