一. 继承关系
- 继承可以解决类与类之间代码重复的问题。
- 体现了一个体系。
![image][extends]
基于某个父类对对象的定义加以拓展,而产生新的子类,子类可以继承父类原来的某些定义,也可以
增加原来父类所没有的定义,或者父类中的某些特性。
从面向对象的角度上说:继承是一种从一般到特殊的关系,是一种“is a”的关系,即子类是父类的
拓展,是一种特殊的父类。
- 语法格式:在定义,子类的时候来表明自己需要拓展于哪一个父类。
public class 子类类名 extends 父类类名{
编写自己特有的状态和行为;
}
在Java中,类和类之间的继承关系只允许单继承,不允许多继承。
一个类只能有一个直接父类。A类只能继承一个父类。
但是Java中允许多重继承。A类能继承一个父类,B类能继承一个A类。
在Java中除了Object类之外,每一个类都有一个直接父类。
Object类是Java语言的根类
新建ExtendsDemo.java
//继承Demo
//人
class Person
{
String name;
int age;
public void sleep(){};
}
//学生类
class Student extends Person
{
String sn;//学号
}
//教师类
class Teacher extends Person
{
String level;//级别
}
//员工类
class Employee extends Person
{
String hireDate;//入职时间
}
class ExtendsDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
- 子类所继承的父类成员情况:
- 父类成员用public修饰。可继承
- 父类成员用protected修饰。 可继承
- 在同一个包中的父类中的缺省成员。.可继承
- 父类成员用private修饰。可以继承,但是子类无法直接访问,可以通过父类的非private方法访问
- 父类的构造器。不能继承
修改ExtendsDemo.java
//继承Demo
//人
class Person
{
public String name;
int age;
protected int num;
private void sleep(){};
}
...
//员工类
class Employee extends Person
{
String hireDate;//入职时间
}
class ExtendsDemo
{
public static void main(String[] args)
{
Employee e = new Employee();
e.name = "hk";
e.age = 2;
e.num = 2;
e.sleep();
}
}
二. 方法覆盖
- 覆盖:当父类的某一个行为不符合子类具体的特征的时候,此时子类需要重新定义父类的方法,并重写
方法体。
只有方法存在覆盖的概念,字段没有覆盖。
-
一同:
- 实例方法签名必须相同。(方法签名=方法名+方法的参数列表)
-
两小:
- 子类方法的返回值类型是和父类方法或者是其子类方法返回值相同。
子类可以返回一个更加具体的类型。 - 子类方法声明抛出的异常类型和父类方法声明抛出异常类型相同或者是其子类
子类方法中声明抛出的异常小于或等于父类方法声明抛出异常类型。
子类方法可以同时声明抛出多个属于父类方法声明抛出异常类的子类
(RuntimeException类型除外)
- 子类方法的返回值类型是和父类方法或者是其子类方法返回值相同。
-
一大:
- 子类方法的访问权限比父类方法访问权限更大或者相等。
private修饰的方法不能被覆盖,所以不存在覆盖的概念。
- 子类方法的访问权限比父类方法访问权限更大或者相等。
-
@Override标签:若方法是复写方法,在方法前或上贴上该标签,编译通过,否则编译报错。
- 方法重载(Overioad)和方法覆盖(OVerride)的区别:
- 方法重载:
- 作用:解决了同一个类中,相同功能的方法名不同的问题。
既然相同的功能,那么名字就应该相同。 - 规则:两同一不同。
同类中,方法名相同,方法参数列表不同(参数类型,参数个数,参数顺序)
- 方法覆盖:
- 作用:解决子类继承父类之后,可能父类的某一个方法不满足子类的具体特征,此时需要重新在子
类中定义该方法,并重新写方法体。 - 规则:一同两小,一大。
- 一同:父类个子类方法签名相同。
- 作用:解决子类继承父类之后,可能父类的某一个方法不满足子类的具体特征,此时需要重新在子
新建BirdDemo.java
//覆盖方法Demo
//鸟类
class Bird extends Object
{
void fly(){
System.out.println("我在仰望~自由飞翔~");
}
}
//企鹅
class Penguin extends Bird
{
void fly(){
System.out.println("有多少梦想在自由的飞翔~");
}
}
class BirdDemo
{
public static void main(String[] args)
{
Penguin p = new Penguin();
p.fly();
}
}
三. 隐藏
-
满足继承的访问权限下,隐藏父类静态方法:若子类定义的静态方法的签名和超类中的静态方法签名相同,那么此时就是隐藏父类方法。注意:仅仅是静态方法,子类存在和父类一模一样的静态方法.
-
满足继承的访问权限下,隐藏父类字段:若子类中定义的字段和超类中的字段名相同(不管类型),此时就是隐藏父类字段,此时只能通过super访问被隐藏的字段。
-
隐藏本类字段:若本类中某局部变量名和字段名相同,此时就是隐藏本类字段,此时只能通过this访问被隐藏的字段。
static不能和super以及this共存.
四. super关键字
- this:表示当前对象。
- super:表示当前对象的父类对象
新SuperDemo.java
//Super的Demo
//鸟类
class Bird extends Object
{
void fly(){
System.out.println("我在仰望~自由飞翔~");
}
}
//企鹅
class Penguin extends Bird
{
void fly(){
System.out.println("有多少梦想在自由的飞翔~");
}
void sing(){
System.out.println("使用super父类的fly()方法");
super.fly();
}
}
class SuperDemo
{
public static void main(String[] args)
{
Penguin p = new Penguin();
p.sing();
}
}
五. 子类初始化的过程
创建子类对象时执行顺序是:先进入子类构造器,然后在构造器中会先调用父类构造器(创建父类),
再执行子类构造器代码。
- 如果父类不存在可以被子类访问的构造器,则不能存在子类。
- 如果父类没有提供无参构造器,此时子类必须显示通过super语句去调用父类带参的构造器。
新建AnimalDemo.java
//子类的初始化过程
//动物类
class Animal
{
private int age;//私有整型的变量
private String name;//私有字符串变量
Animal(int age,String name){
this.age = age;
this.name = name;
}
int getAge(){
return age;
}
String getName(){
return name;
}
}
//鱼类
class Fish extends Animal
{
String color;
Fish(int age,String name,String color){
//父类没有无参的构造函数得使用super来调用父类有参的构造函数
super(age,name);
this.color = color;
}
void show(){
System.out.println(getAge() + "\n" + getName() + "\n" +color+ "\n" );
}
}
class AnimalDemo
{
public static void main(String[] args)
{
Fish f = new Fish(4,"hk","黄色");
f.show();
}
}
六. Object类
- Object类是所有类的父类,或间接父类。
class ABC{}等价于class ABC extends Object{}
-
所有对象(包括数组)都实现这个类的方法。
Object本身指对象的意思,我们发现所有的对象都具有某一些共同的行为,所以抽象出一个
类:Objcet,表示对象类,其他都会继承Object类,也就拥有Object类中的方法。
引用数据类型:类、接口,数组,引用类型又称之为对象类,所谓的数组变量名称,应该指数组对象。 -
Object类的常见方法:
- protected void finalize():当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器
调用此方法,垃圾回收器在回收某一个对象之前,会调用该方法,做扫尾操作,该方法我们不要
去调用。 - Class getClass():返回当前对象的真实类型
- int hashCode():返回该对象的哈希码值,hashCode决定了对象在哈希表的中存储位置,不
同对象的hashCode是不一样的。 - boolean equals(Object obj):拿当前当前对象(this)和参数obj做比较。
在Object类中的equals方法,本身和“==”方法相同,都是比较对象的内存地址,
String类覆盖了equals方法,所以能比较两个字符串的数据。
官方建议:每个类都应该覆盖equals方法,不要比较内存地址,而去比较数据。 - String toString()表示把一个对象转换为字符串。
打印对象时,其实打印的就是对象的toString()方法。
System.out.println(obj对象);等价于System.out.println(obj对象.toString);
默认情况下打印对象,打印的是对象的十六进制的hashCode值,但是我们更关心对象中
存储的数据。
- protected void finalize():当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器
-
官方建议我们:应该每个类都应该覆盖toString()方法,返回我们关心的数据。
println打印对象的底层。
新建ObjectDemo.java
//Object的Demo
class User
{
int age;
String name;
public String toString(){//重写toString方法
return age + "," + name;
}
}
class ObjectDemo
{
public static void main(String[] args)
{
User u = new User();
System.out.println(u.getClass());//返回此时Object运行的对象
System.out.println(u.hashCode());//返回该对象的哈希码值
System.out.println(u);
}
}