在面向对象中类和类可以存在继承关系。即将若干个类中相同的内容(变量,函数)进行提取,把提取出来的内容放到一个类里面,这个类称为父类,其他几个被抽取的类成为子类。
子类与父类之间的关系就是继承关系。一个子类只能有一个父类。在继承的时候子类和父类之间必须符合现实生活中的定义。子类从逻辑上而言应该是父类中的一种从属关系,不能因为代码的重复而忽略逻辑。
在java中有许多体系,例如:
Number体系---数字家族
Integer
Double
Long
在java中也存在继承,并且java是一种典型的单继承语言。即一个类最多只能有一个父类,不能有多个父类。
【子父类中成员变量的特点】
子类对象在创建的时候,堆内存中对象的空间里
(1)先对子类对象的成员变量进行创建并默认初始化
(2)再对父类的成员变量进行创建并默认初始化-在对象空间中的super空间里
(3)对应子类的构造函数进栈-执行显示初始化(子类父类的成员变量都显示初始化)
当调用子类对象的变量son.num时
寻找的过程为:子类成员变量 -----子类的静态变量------父类成员变量
在子类成员函数中调用变量时
寻找过程为:函数内部局部变量----子类成员变量----子类的静态变量---父类成员变量
如果前面有super修饰的话,就直接去父类空间找
【子父类中构造函数的特点】
子类的构造函数调用的时候,父类的构造函数也执行了,并且在子类构造函数之前,
因为子类的构造函数中,如果第一句不是this(),那么就是super()
super()默认调用的是父类的无参构造函数,但是在执行父类构造函数的时候并没有
创建父类对象,其目的就是为了给子类即将继承的数据进行初始化(显示初始化--针对初始化)
关于this()和super()
子类的构造函数最终都需要先调用父类的构造函数
(1)子类构造函数第一句是super()那么直接调用父类的构造函数
(2)子类构造函数第一句是this()----那么还是调用父类的构造函数。
即子类所有构造函数的第一行都有一条隐身的语句super():
1、父类有空参构造函数:没有有参构造时,系统默认给出了,或者有有参构造并
且也给出了空参构造,此时子类自动调用父类构造函数
2、如果父类没有空参构造函数:有有参构造函数但是并没有空参构造时,子类在构
造函数第一句又会默认调用父类的空参构造,即调用隐身的super(),此时会编译
出错。在手动写出空参构造时,就能解决。
【子父类中成员函数的特点】
子父类中成员函数的特点和子父类中成员函数的调用形式很像
如果父类没有,子类有则调用子类的
如果父类有,子类没有则调用父类的
如果父类有,子类也有,则调用子类的
【子父类中静态变量的特点】
静态变量的特点同成员变量
父类有,子类无 调用的就是父类的
父类无,子类有 调用的是子类的
父类有,子类有,调用的是子类的
1、Java如何实现继承:extends关键字。
public class Son extends Father{
//son继承father
}
2、继承的功能:减少代码的重复,增加代码的复用度。
注意:private修饰的方法或者属性无法被子类继承。
protected修饰的方法或者属性就是用来给子类继承的。
package jicheng;
public class Father {
public int money = 100000000;
protected String company = "tencent";
String car = "摇摇车";
private String mishu = "小秘";//父类的秘书是private的
}
package jicheng;
public class Son extends Father{
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.money);
System.out.println(son.car);
System.out.println(son.company);
System.out.println(son.mishu);//此时子类不能继承父类的秘书,这里会报错
}
}
3、方法重写(覆盖):
重写(OverWrite)覆盖(OverRide):发生在继承中,指的是子类在继承父类
的方法后,该方法无法满足子类使用,所以在子类中重写该方法,以达到满足
子类使用的目的。
在子类中重写父类的方法时有以下注意点:
1、权限修饰符相比于父类的方法,只能扩大或者相等,不能缩小。
2、返回值类型不能发生变化
3、函数名称与父类的函数名称一致
4、参数列表必须保持一致
package jicheng;
public class Father {
protected void say(){
System.out.println("全体目光向我看齐");
}
}
package jicheng;
public class Son extends Father{
protected void say(){
System.out.println("我宣布一个事");
}
public static void main(String[] args) {
Son son = new Son();
son.say();//此时执行的是子类里面的say函数,而不是父类
}
}
4、注解(annotation):
JDK5.0提供的新特性,利用反射技术,可以很轻松使用标注属性、方法、类等。
从而扩展功能。
注解一:@Override(表示重写方法)
注解二:@Deprecated(表示过时警告)
注解三:@SuppressWarnings(压制警告)
public class Son extends Father{
@Override//注解,意思是say函数为重写方法
protected void say(){
System.out.println("我宣布一个事");
}
5、super关键字:
super在java中是一个指针,类似于this指针。
this指针会指向创建的每一个对象
super指针指向父类
package jicheng;
public class Son extends Father{
protected void say(){
System.out.println("我宣布一个事");
}
public void sayhello(){
this.say();//调用的是子类自身的say函数
super.say();//调用的是父类的say函数
}
public static void main(String[] args) {
Son son = new Son();
son.sayhello();
}
}
6、对象的创建流程:
(1)使用java命令将源码(.java)进行编译,生成字节码(.class)文件
(2)javac执行字节码文件
(3)将字节码文件加载进虚拟机(JVM),静态方法区开始加载静态资源
(4)JVM从静态方法区读取主函数,并加载进栈(执行栈被创建了出来)
(5)main函数开始执行创建对象的代码Son son = new Son();
(6)在堆内存中开辟对象的内存空间,并分配地址
(7)创建成员变量并进行默认初始化
(8)子类构造函数从非静态方法区加载进栈开始执行
(9)第一句先执行父类的构造函数
(10)父类构造函数执行,为子类继承到的成员变量进行初始化(对象内存空
间里的父类空间)
(11)父类构造函数弹栈完成
(12)子类构造函数继续执行,此时先对成员变量进行显式初始化
(13)再执行子类构造函数的内容,进行针对性初始化
(14)执行完成,子类构造函数弹栈,将对象的内存空间地址赋予相应的引
用变量
子类对象在创建的时候子父类中成员变量的特点:
堆内存中对象的空间里
(1)先对子类对象的成员变量进行创建并默认初始化
(2)再对父类的成员变量进行创建并默认初始化-在对象空间中的super空间
(3)对应子类的构造函数进栈-执行显示初始化(子类父类的成员变量都显
示初始化)
通过子类对象调用变量 son.num
寻找过程:子类成员变量----子类的静态变量----父类成员变量
在子类成员函数中调用变量
寻找过程:函数内部局部变量----子类成员变量----子类的静态变量---父类成员变量
如果有super直接去父类空间找
关于this()和super():子类的构造函数最终都需要先调用父类的构造函数
(1)子类构造函数 第一句是super()那么直接调用父类的构造函数
(2)子类构造函数 第一句是this()那么调用this(),一直往下,子类的最终被调用
的构造函数不能回调 遇到第一句是super()的构造函数,那么就调用父类的构造
函数。
this():调用本类中的无参构造函数
super():调用父类中的一个无参构造函数
7、instanceof关键字:
instance:实例
instanceof:判断是否是实例
public static void main(String[] args) {
Xiugou xiugou = new Xiugou();
System.out.println(xiugou instanceof Xiugou);//判断xiugou是否是Xiugou类的一个实例,如果是,返回true。
}
8、字符串格式化的方法:
format():静态方法
相当于System.out.printf()
public static void main(String[] args) {
String name = "高" ;int age = 16 ;String address = "陕西";
System.out.println(String.format("我的名字叫做%s , 我今年%d岁了,我来自%s。" ,name , age , address));
}
9、final关键字:
final:最终、最后,可以修饰基本数据类型,引用数据类型,函数,类。
(1)被final修饰的变量,就不能被重新赋值了,就成为了一个常量
定义常量:static final double PI = 3.14 ;//常量的每个字母都要大写
定义常量只能定义在类里面,不能定义在方法里面。
public class Test52 {
static final double PI = 3.14;
}
(2)final除了修饰常量外,还可以修饰类和方法,如果final修饰了方法,该方法无法被重写(override)。
class Animal{
protected final void say(){ //父类say方法被final修饰
System.out.println("我是一个动物。");
}
}
class Xiugou extends Animal{
protected void say(){ //子类重写say方法时会出现编译型错误
System.out.println("汪汪汪,我是一个傻狗。");
}
(3)final也可以修饰类,一旦某个类被final修饰,该类将断子绝孙,无法被
继承。
10、内部类:定义在一个类内部的类,叫做内部类。
class Xiumao{
class Lihuamao{
}
}
(1)内部类可以看成外部类的一个成员。
(2)内部类可以直接访问包含它的类的私有成员。
class Xiumao{
private int age = 10 ;//将age定义为私有成员
class Lihuamao{
public void say(){
System.out.println(age);//内部类可以访问这个私有成员
}
}
}
(3)从别的类不能直接访问到内部类的成员,如果要访问,
就必须定义内部类对象,利用这个对象来访问内部类成员
public static void main(String[] args) {
//定义一个内部类的对象,前提是内部类不是静态和私有的内部类
Xiumao.Lihuamao lihuamao = new Xiumao().new Lihuamao();
lihuamao.say();
}
如果内部类是静态类,可以直接定义对象。
public static void main(String[] args) {
Xiumao.Lihuamao lihuamao = new Xiumao.Lihuamao();
}
(4)当内部类中需要存在静态内容,该内部类必须定义为静态内部类
静态内部类中不能直接访问外部类中的非静态成员,但是非静态内部部类可以
11、static关键字静态导包:
如果需要使用一个静态方法,该方法需要导包,可以使用静态导包的方法。如果
静态导包成功,那么就可以直接使用静态方法的名称。
import static java.util.Arrays.sort;//静态导入sort方法包
public class Test52 {
public static void main(String[] args) {
int arr[] = {12,1,4,3,6,8,9,0};
sort(arr);//直接使用sort方法
}