1、面向对象(继承-概述)
//定义一个学生
class Student
{
String name;
int age;
void study()
{
system.out.println("study");
}}
//定义一个工人
class Worker
{
String name;
int age;
void work()
{
system.out.println("work");
}}
我们想把上面俩个类中的name和age共性的内容抽取出来。单独进行描述。
只要让学生和工人与单独描述的这个类有关系。
class Person
{
String name;
int age;
}
class Student extends Person//子类Student继承父类Person
{
void study()
{
system.out.println("study");
}
}
class Worker extends Person
{
void work()
{
system.out.println("work");
}}
继承:
1,提高代码的复用性。
2,让类与类之间产生了关系。有了这个关系,才有了多态的特性。
注意:千万不要为了获取其他类的功能,简化代码而继承。
必须是有类与类之间有所属关系。才可以继承。
2、面向对象(继承-概述2)
class C
{
void demo1(){}
}
class A extendsC
{
//void demo1(){}
void demo2(){}
}
class B extendsC
{
//void demo1(){}
void demo3(){}
}
A和B都可以继承C。先有父类。然后子类再引用。
Java语言中:java只支持单继承,不支持多继承。
因为多继承容易带来安全隐患。当多个父类的功能相同,但是内容不同,不确定要运行哪一个。但是java保留了这种机制。通过:"多实现"完成。
class A
{
void show()
{
system.out.println("a");
}
class B
{
void show()
{
system.out.println("b");
}
}
class C extends A,B//多继承
{
C c=new C();//这样就不确定打印的是A,还是B.
c.show();
}
java支持多层继承(嵌套继承,C继承B,B继承A,),也就是一个继承体系。
如何使用一个继承体系中的功能呢?
想要使用体系,先查阅体系父类的描述。因为父类定义的是该体系中的共性内容。
通过了解共性功能,就可以知道该体系的基本功能。
那么具体调用时,要创建最子类对象。为什么???
1,可能父类不能创建对象。
2,创建子类对象可以使用更多的功能,包括基本的(父类)也包括特有的。
简单一句话:查阅父类功能,创建子类对象使用功能。
3、面向对象(子父类中变量的特点)
子父类出现后,类成员的特点:
类中成员:
1,变量2,函数3,构造函数
class Fu
{
int num1 = 4;
}
class Zi extends Fu
{
int num2 = 5;
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();
system.out.println(z.num1+"..."+z.num2);//打印4...5
}
对比:子类和父类的变量名相同是:
class Fu
{
int num=4;
}
class Zi extends Fu
{
int num=5;//先加载父类的num=4;然后子类的变量num=5覆盖了父类
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();
system.out.println(z.num+"..."+z.num);//打印5...5。打印的是子类num。
}
如果要打印Fu类中的内容时,用super变量。
class Fu
{
int num=4;
}
class Zi extends Fu
{
int num=5;
void show()
{
system.out.println(super.num);//super代表父类的引用。
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();
z.show();//打印4
}
如果子类出现非私有的同名成员变量时
1,访问本类中的变量,用this
2,访问父类中的变量,用super
5、面向对象(子父类中函数的特点-覆盖)
子父类中函数的特点:
当子类出现和父类一样的函数时:
当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。
这是函数的一个特性:重写(覆盖)
class Fu
{
void show()
{
system.out.println("fu");
}
}
class Zi extends Fu
{
void show()
{
system.out.println("zi");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
z.show();//打印zi。运行的是子类的内容。
}
当子类继承父类,沿袭父类的功能,到子类中。
但是子类已经具备该功能了,但是功能的内容却和父类不一致。
这时,没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重写功能的内容。
class Fu
{
void show()
{
system.out.println("fu");
}
void speak()
{
system.out.println("vb");
}
}
class Zi extends Fu
{
void speak2()
{
system.out.println("java");
}
void show()//覆盖了父类的
{
system.out.println("zi");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
z.show();//打印zi。运行的是子类的内容。
}
例如:
老手机的功能:
class Tel
{
void show()
{
system.out.println("number");
void lingsheng(){}
}
新手机继承老手机:
class NewTel extendsTel
{
void show()
{
system.out.println("number");//覆盖了父类的内容。
system.out.println("name");
system.out.println("pic");
}
改进新手机
class NewTel extends Tel
{
void show()
{
super.show();//用super引用父类。
system.out.println("name");
system.out.println("pic");
}
覆盖:
1,子类覆盖父类,必须保证子类权限>=父类,才可以覆盖,否则编译失败。
2,静态只能覆盖静态。(因为加载问题,非静态只有调用的时候才加载。)
3,权限从大到小:public>void(一般)>private
class Tel
{
void show()
{....}
class NewTel extends Tel
{
private void show()//编译错误。
{......}
下面这种情况不叫覆盖。
class Tel
{
private void show()//父类私有化。子类不知道有这个东西。
{....}
class NewTel extends Tel
{
void show()//编译错误。
{......}
记住:
重载:只看同名函数的参数列表。
重写(覆盖):子父类方法要一模一样。
6、面向对象(子父类中构造函数的特点-子类实例化过程)
class Fu
{
Fu()//父类的构造函数,随着类名走。
{
system.out.println("fu run");
}
}
class Zi extends Fu
{
Zi()
{//super();虚拟机默认自动加在第一行,而且是隐藏起来的。可以不写,也可以写上。调用父类,故先打印父类。
system.out.println("zi run");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();
}
//打印:
fu run
zi run
在对子类对象进行初始化时,父类的构造函数也会运行。
因为子类的构造函数的第一行有一条隐藏式的语句super();
super();会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行为super()
改成下面的值,也是没有影响的。
class Fu
{
Fu()
{
system.out.println("fu run");
}
Fu(int x)//它不影响空参数构造函数
{
system.out.println("fu...");
}
}
class Zi extends Fu
{
Zi()
{
system.out.println("zi run");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();
}
但是:如果父类没有空参数构造函数的话呢?
class Fu
{//没有
Fu(int x)
{
system.out.println("fu run");
}
}
class Zi extends Fu
{
Zi()
{
system.out.println("zi run");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();//编译报错。这时系统不会自动创建空参数构造函数
}
这时,需要手动设置super()的值,让它指向父类。
class Fu
{
Fu(int x)
{
system.out.println("fu run");
}
}
class Zi extends Fu
{
Zi()
{
super(4);
system.out.println("zi run");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi();//编译通过。
}
另外可以用this(),指向子类
class Fu
{
Fu(int x)
{
system.out.println("fu run");
}
}
class Zi extends Fu
{
Zi()
{
system.out.println("zi run");
}
Zi(int x)
{
this();//这时super()不存在。
system.out.println("zi run");
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi(0);//编译通过。
}
那么,为什么子类一定要访问父类中的构造函数呢?
因为父类中的数据,子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。
所以子类在对象初始化时,要先访问一下父类中的构造函数。
需要访问父类中指定的构造函数,可以手动方式来定义。
class Person
{
private String name;
Person(String name)//提供name的访问方法
{
this.name=name;
}
}
class Student extends Person
{
Student(String name)
{
super(name);//直接拿来用就行了。
}
}
结论:子类的所以构造函数,默认都会访问父类中空参数的构造函数。因为子类有super()
当父类中没有空参数的构造函数时,子类必须手动通过super调用。
当然:子类的构造函数第一行也可以手动指定this访问本类的构造函数。
子类中至少会有一个构造函数访问父类中的构造函数。
这就是子类的实例化过程。
class Fu//这里也会默认为classFu extends object。继承最基本的对象
{
//这里默认也会有个super();
Fu()
{
system.out.println("fu run");
}
Fu(int x)
{
system.out.println("fu run");
}
}
class Zi extends Fu
{
Zi()
{
system.out.println("zi run");
}
Zi(int x)
{
this();
system.out.println("zi run");
}}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z=new Zi(0);
}}
问题明确下:
为什么this和super不能在同一行?(不能同时在构造函数当中)
因为他们都只能写在第一行。
为什么写第一行?
因为初始化动作要先做。