目录
一、简介:
- 是一种类与类之间的关系。
- 使用已存在的类的定义作为基础建立新类。
- 新类的定义可以增加新的数据或新的功能,也可用父类的功能,但不能选择性地继承父类。
- 特点:①利于代码复用 ②缩短开发周期
满足“A is a B”的关系就可形成继承关系。
二、继承的实现:
父类:
class Animal{
//公共的属性和方法
}
子类(继承父类):通过extends关键字实现继承
class Dog extends Animal{
//子类特有的属性和方法
}
class Cat extends Animal{
}
注意只能是单一继承,一个子类只能有唯一的父类
例:
Eclipse如何创建继承关系?生成子类时在Browse那行选择父类即可。
Animal类:
package com.animal;
public class Animal {
private String name;
private int month;
private String species;
//父类的构造方法既不允许被子类继承,也不允许被重写。
public Animal() {
System.out.println("我是父类的无参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//吃东西
public void eat() {
System.out.println(this.getName()+"在吃东西");
}
}
Cat类:
package com.animal;
public class Cat extends Animal {
private double weight; //体重
//无参构造
public Cat() {
System.out.println("我是子类的无参构造方法");
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//跑方法
public void run() {
System.out.println(this.getName()+"是一只"+this.getSpecies()+"品种的猫,它在奔跑");
}
}
Dog类:
package com.animal;
public class Dog extends Animal {
private String sex;
public Dog() {
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
//睡觉
public void sleep() {
System.out.println(this.getName()+this.getMonth()+"几个月大,在睡觉");
}
public void eat() {
System.out.println(this.getName()+"最近没有食欲~");
}
//方法重写
public void eat(String name) {
System.out.println(name+"最近没有食欲~");
}
}
Test类:
package com.test;
import com.animal.Cat;
import com.animal.Dog;
public class Test {
public static void main(String[] args) {
Cat one=new Cat();
one.setName("荣耀");
one.setSpecies("银渐层");
one.eat();
one.run();
System.out.println("===========================");
Dog two =new Dog();
two.setName("小黑");
two.setMonth(1);
two.eat();
two.sleep();
System.out.println("===========================");
two.eat("fanfan");
}
}
结果:
子类能获取父类非私有的成员,父类不能访问子类的特有成员。
1.方法重载要求满足:
①要在同一个类中。
②方法名相同,参数列表不同(参数顺序、个数、类型) 。
③方法的返回值、访问修饰符任意
④方法的参数名任意(如果仅仅是参数名不同,参数类型,参数顺序没有区别也无法构成重载)。
2.方法重写要求满足:
方法的返回值类型、方法名、参数类型、顺序、个数都要与父类继承的方法相同。
①有继承关系的子类中。
②方法名、参数列表相同(参数类型、个数、类型)与父类相同。注意:方法返回值可以与父类不同,允许是子类类型。
③方法的访问修饰符是允许可以有变化的(条件:访问修饰符的限定范围≥父类方法)。
④与方法参数名无关(不强制要求相同)。
父类的构造方法既不允许被子类继承,也不允许被重写。
3.访问修饰符:
访问 范围 | 本类 | 同包 | 子类 | 其他 | 限制 能力 | |
大 ⬇ 小 | pulic | ✔ | ✔ | ✔ | ✔ | 小 ⬆ 大 |
protected | ✔ | ✔ | ✔ | |||
默认 | ✔ | ✔ | ||||
private | ✔ |
4. 继承后的初始化顺序:
在执行程序时,先完成类的加载。
类在加载时,会优先加载父类的静态信息,然后是子类的静态信息。 加载父类时,会先去加载父类地成员属性,然后执行构造代码块,最后执行构造方法。Object是所有类的父类。
在构造子类对象时,会依次地先去找父类(先构造父类),如果父类还有父类则会追根究源,再依次进行实例化操作。如图:
注意在进行静态信息加载时,访问修饰符不影响成员加载顺序,与书写位置有关。
三、super关键字:
①在继承关系中,子类的构造过程中(即调用子类的构造方法)要调用父类的构造方法。若子类的构造方法中未显式标注,则系统默认调用父类的无参构造。故无参构造很重要!!!
如果子类构造方法中既未显示标注,且父类中也无无参构造方法,就会编译出错。可见,虽然父类的构造方法不可被继承、不可被重写,但会影响子类对象的实例化。
②可以通过:super(参数1,参数2,..); 去指定调用父类允许被访问的其他构造方法。但注意super()语句必须放在子类构造方法有效代码的第一行。super()调用父类的无参构造方法。
③总结:
- super关键字代表父类引用:
-访问父类成员方法:super.print();
-访问父类属性:super.name;
-访问父类构造方法:super();
④super和this对比:
this(当前类对象的引用) | super(父类对象的引用) | |
同 | 访问当前类的成员方法 访问当前类的成员属性 访问当前类的构造方法 | 访问当父类的成员方法 访问当父类的成员属性 访问当父类的构造方法 |
异 | 不能在静态方法中使用 |
注意:在构造方法中,super和this不能并存,因为它们都要抢占第一行,只能有一个。
四、Object类:
1.简介:
- Object类是所有类的父类。
- 1个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)。
- Java中的每个类都可使用Object中定义的方法。
Java SE8 API链接:https://docs.oracle.com/javase/8/docs/api/
Object类存放在java.lang包中
2.Object类的一些方法:
例:
①equals方法:
package com.test;
import com.animal.Cat;
public class Test2 {
public static void main(String[] args) {
Cat one = new Cat("谦卑", 2); // 父类的带参构造方法
Cat two = new Cat("谦卑", 2);
// Object类的equals方法:比较2个引用是否指向同一对象
boolean a = one.equals(two);
System.out.println("one和two的引用比较:" + a);
System.out.println("one和two的引用比较:" + (one == two));
System.out.println("==============================");
String str1 = new String("hello");
String str2 = new String("hello");
a = str1.equals(str2);
System.out.println("str1和str2的引用比较:" + a); //String类自己重写了Object类的equals方法:只比较字符串内容
System.out.println("str1和str2的引用比较:" + (str1 == str2));
}
}
继承Object中的equals方法时,比较的是两个引用是否指向同一个对象。子类可以通过重写equals方法来改变比较的内容,如只想比较对象one和two的值:
修改:
package com.animal;
public class Animal {
private String name;
private int month;
private String species;
//父类的构造方法既不允许被子类继承,也不允许被重写。
public Animal() {
System.out.println("我是父类的无参构造方法");
}
public Animal(String name, int month) {
this.name = name;
this.month = month;
System.out.println("我是父类的带参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//吃东西
public void eat() {
System.out.println(this.getName()+"在吃东西");
}
//equals方法重写
public boolean equals(Object obj){
if(obj==null)
return false;
Animal temp=(Animal)obj; //强制类型转换:Object型转Animal型
if(this.getName().equals(temp.getName()) && (this.getMonth()==temp.getMonth()))
return true;
else
return false;
}
}
package com.test;
import com.animal.Animal;
public class Test2 {
public static void main(String[] args) {
Animal one=new Animal("花花",2); // 父类的带参构造方法
Animal two=new Animal("花花",2);
boolean flag=one.equals(two);
System.out.println("one 和 two的引用比较:"+flag);
System.out.println("one 和 two的引用比较:"+(one==two));
System.out.println("======================================");
String str1=new String("hello");
String str2=new String("hello");
flag=str1.equals(str2);
System.out.println("str1 和 str2的引用比较:"+flag); //String类自己重写了Object类的equals方法:只比较字符串内容
System.out.println("str1 和 str2的引用比较:"+(str1==str2));
}
}
改进:
package com.animal;
public class Animal {
private String name;
private int month;
private String species;
//父类的构造方法既不允许被子类继承,也不允许被重写。
public Animal() {
System.out.println("我是父类的无参构造方法");
}
public Animal(String name, int month) {
this.name = name;
this.month = month;
System.out.println("我是父类的带参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//吃东西
public void eat() {
System.out.println(this.getName()+"在吃东西");
}
/*
* //equals方法重写 public boolean equals(Object obj){ if(obj==null) return false;
* Animal temp=(Animal)obj; //强制类型转换:Object型转Animal型
* if(this.getName().equals(temp.getName()) &&
* (this.getMonth()==temp.getMonth())) return true; else return false; }
*/
//equals方法重载,避免强制类型转换
public boolean equals(Animal obj){
if(obj==null)
return false;
if(this.getName().equals(obj.getName()) && (this.getMonth()==obj.getMonth()))
return true;
else
return false;
}
}
②toString方法:
- 输出对象名时,默认会直接调用类中的toString方法
- 继承Object类中的toString方法时,输出对象的字符串表示形式:类型信息+@+地址信息
package com.test;
import com.animal.Animal;
public class Test2 {
public static void main(String[] args) {
Animal one=new Animal("花花",2); // 父类的带参构造方法
Animal two=new Animal("花花",2);
/*
* boolean flag=one.equals(two); System.out.println("one 和 two的引用比较:"+flag);
* System.out.println("one 和 two的引用比较:"+(one==two));
* System.out.println("======================================"); String str1=new
* String("hello"); String str2=new String("hello"); flag=str1.equals(str2);
* System.out.println("str1 和 str2的引用比较:"+flag);
* //String类自己重写了Object类的equals方法:只比较字符串内容
* System.out.println("str1 和 str2的引用比较:"+(str1==str2));
*/
System.out.println(one.toString());
System.out.println(one);
}
}
重写toString方法:
package com.animal;
public class Animal {
private String name;
private int month;
private String species;
//父类的构造方法既不允许被子类继承,也不允许被重写。
public Animal() {
System.out.println("我是父类的无参构造方法");
}
public Animal(String name, int month) {
this.name = name;
this.month = month;
System.out.println("我是父类的带参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//吃东西
public void eat() {
System.out.println(this.getName()+"在吃东西");
}
/*
* //equals方法重写 public boolean equals(Object obj){ if(obj==null) return false;
* Animal temp=(Animal)obj; //强制类型转换:Object型转Animal型
* if(this.getName().equals(temp.getName()) &&
* (this.getMonth()==temp.getMonth())) return true; else return false; }
*/
/*
* //equals方法重载,避免强制类型转换 public boolean equals(Animal obj){ if(obj==null) return
* false; if(this.getName().equals(obj.getName()) &&
* (this.getMonth()==obj.getMonth())) return true; else return false; }
*/
//重写toString方法
public String toString() {
return "昵称:" +this.getName()+";年龄:"+this.getMonth();
}
}
package com.test;
import com.animal.Animal;
public class Test2 {
public static void main(String[] args) {
Animal one = new Animal("花花", 2); // 父类的带参构造方法
Animal two = new Animal("花花", 2);
/*
* boolean flag=one.equals(two); System.out.println("one 和 two的引用比较:"+flag);
* System.out.println("one 和 two的引用比较:"+(one==two));
* System.out.println("======================================"); String str1=new
* String("hello"); String str2=new String("hello"); flag=str1.equals(str2);
* System.out.println("str1 和 str2的引用比较:"+flag);
* //String类自己重写了Object类的equals方法:只比较字符串内容
* System.out.println("str1 和 str2的引用比较:"+(str1==str2));
*/
String str1=new String("hello");
System.out.println(one.toString());
System.out.println(one);
System.out.println("======================================");
System.out.println(str1); //String类重写了toString方法,使输出字符串的值
}
}
五、final关键字:
1.对类:
- 在class前面添加final关键字,表示最终的,表示该类不允许有子类、不能被继承、是终极类。
- final的位置可以与访问修饰符互换,只要写在class关键字前面就行。
public final class Animal{
}
或:
final public class Animal{
}
2.对方法:
在方法的返回值前添加final关键字表示该方法不希望被子类重写,但是可以正常被子类继承使用。
public final void eat() {
}
注意final不能修饰构造方法。
3.对变量:
- 修饰方法内的局部变量:在数据类型前添加final关键字,表示该变量只要在具体使用之前进行赋值即可,一旦赋值不允许被修改。
public void eat(){
final int a=10; //方法内的局部变量
}
- 修饰类中的成员属性:如果在定义时没有进行初始化赋值,则只允许在构造方法和构造代码块里对齐赋值。
public class Animal{
public final int a=15;
}
4.对不同数据类型:
- 修饰基本数据类型:初始赋值后不能修改
- 修饰引用数据类型:初始化后不能再指向另一个对象,但指向的对象内容是可变的。
package com.animal;
public class Animal {
private String name;
private int month;
private String species;
//父类的构造方法既不允许被子类继承,也不允许被重写。
public Animal() {
System.out.println("我是父类的无参构造方法");
}
public Animal(String name, int month) {
this.name = name;
this.month = month;
System.out.println("我是父类的带参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//吃东西
public void eat() {
System.out.println(this.getName()+"在吃东西");
}
public void eat(String name) {
final int temp; //方法内的局部变量
System.out.println(name+"在吃东西");
temp=12;
System.out.println(temp);
final Animal animal=new Animal("fanfan",1);
/* animal=new Animal(); */ //报错,不能修改引用
animal.month=12;
animal.name="doudou"; //属性值可修改
}
}
5.和static关键字一起使用:
- 表示全局的不允许被修改的内容
- 修饰程序中的配置信息:表示只需要加载一次又不需要后续修订的内容
6.特点:
使用final关键字可提高性能,但会降低可扩展性、灵活性,需慎重使用。
六、注解:
如何快速重写父类方法?
Alt+/显示提示菜单的信息
- 是JDK1.5版本引入的一个特性。
- 可以声明在包、类、属性、方法、局部变量、方法参数......前面,用来对这些元素进行说明、注释。
- 添加注释相当于打上了某种标记。
@override表示对父类方法重写,可以用来检测重写的方法是否合理。
元注解:用来对注解进行注释。