继承
继承作用
代码复用,提高开发效率和程序的扩展性。
继承语法
① Java类中的继承的语法格式:
class A{}
class B extends A{} 子承父业
A 就是B的父类、基类、根类、超类
B是A的子类、派生类、拓展类
② 验证:子类中是否可以继承到父类中的东西(通过创建子类对象来操作从父类继承的东西)
代码示例
案例代码:
父类:
public class Animal {
String name;
int age;
public void eat() {
System.out.println("吃");
}
}
子类:
public class Person extends Animal{
/**
* 人类独有方法
*/
public void coding() {
System.out.println("敲代码...");
}
}
public class Pig extends Animal{
/**
* 猪类独有方法
*/
public void gongBaiCai() {
System.out.println("拱白菜...");
}
}
public class Bird extends Animal{
/**
* 鸟类独有方法
*/
public void fly() {
System.out.println("飞...");
}
}
测试类:
/**
* 继承测试类
*/
public class AnimalTest {
public static void main(String[] args) {
//创建子类对象
Person person = new Person();
Pig pig = new Pig();
//通过子类对象调用父类继承过来的成员
person.name = "张三";
person.age = 1;
person.eat();
System.out.println(person.name);
System.out.println(person.age);
//调用子类特有方法
person.coding();
pig.name = "佩奇";
pig.age = 7;
pig.eat();
System.out.println(pig.name);
System.out.println(pig.age);
//调用子类特有方法
pig.gongBaiCai();
}
}
子类可以从父类继承的成员
除了构造方法不能被继承其他都可以继承过来
但是,私有化成员不能直接通过子类对象直接访问,但是可以通过继承过来的公共方法间接访问 示例代码:
public class Animal {
String str;
private int a;
static int b;
public Animal() {
System.out.println("无参构造...");
}
public Animal(int a) {
System.out.println("有参构造...");
}
public void test() {
System.out.println("普通方法");
}
public static void testStatic() {
System.out.println("静态方法..");
}
private void testPrivate() {
System.out.println("私有化方法..");
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
public class Person extends Animal{
/**
* 人类独有方法
*/
public void coding() {
System.out.println("敲代码...");
}
}
测试代码:
/**
* 测试继承哪些成员
*/
public class AnimalTest {
public static void main(String[] args) {
//创建子类对象
Person person = new Person();
//通过子类对象调用父类继承过来的普通成员变量
person.str = "张三";
//通过子类对象调用父类继承过来的私有化成员变量
// person.a = 1;//不能通过子类对象直接调用父类私有化成员
//通过子类对象调用父类继承过来的静态成员变量
// person.b = 2;//不要这样用。 这里编译的时候,会将person对象直接编译为类名的方式
//通过子类对象调用父类继承过来的普通方法
person.test();
//通过子类对象调用父类继承过来的静态方法
// person.testStatic();//不要这样用。 这里编译的时候,会将person对象直接编译为类名的方式
//通过子类对象调用父类继承过来的私有化方法
// person.testPrivate();//不能直接调用私有化方法
//子类调用可以通过父类公共方法间接调用父类中私有化的成员
person.setA(69);
int a = person.getA();
System.out.println(a);//69
//调用Object继承过来的方法
int hashCode = person.hashCode();
System.out.println(hashCode);
}
}
Java中类的继承特点
① 单继承(一个类只能够有一个直接父类)
② 多重继承(多层级的继承), 一个类可以有子类,子类还可以子类...
代码示例:
class A{}
class B extends A{}
class C extends B{}
class D extends C{}
---Animal
---Person extends Animal
---Student extends Person
方法覆写(重写,Override)
方法覆写的作用
保证业务逻辑合理性
方法覆写语法
直接将父类中要重写的方法复制到子类后,重写方法体即可(掌握)
--------------------------以下知道即可------------------------------
1)重写只能出现在继承关系之中。当一个类继承它的父类方法时,都有机会重写该父类的方法。
前提是父类的方法没有被被final(中文意思:最终的,以后讲)修饰
2)子类方法和父类方法的方法签名(方法名+参数列表)完全一致;
3)访问权限 : 子类方法的访问权限 大于等于父类方法的访问权限
4)static/private 方法不能够被重写 (java语法)
5)返回值类型 : 子类方法的返回值类型可以是父类方法的返回值类型的子类或者相等
6)子类抛出的异常(Exception)下是父类相应方法抛出的异常或者相等
代码示例:
public class Animal {
public void eat() {
System.out.println("吃");
}
}
public class Person extends Animal{
@Override//注解,编译期起作用,校验代码
public void eat() {
System.out.println("吃猪");
}
}
public class Pig extends Animal{
public void eat() {
System.out.println("吃白菜。。。。");
}
}
测试代码
/**
* 方法重写测试类
*/
public class AnimalTest {
public static void main(String[] args) {
//创建子类对象
Person person = new Person();
Pig pig = new Pig();
person.eat();//执行子类重写后方法
pig.eat();//执行子类重写后方法
}
}
super关键字
如果调用被覆写的方法不使用 super 关键字,此时调用的是本类中的方法。
super 关键字表示父类对象的意思,super.fly()可以翻译成调用父类对象的 fly 方法
代码示例:
public class Ostrich extends Bird{
public void fly() {
System.out.println("扑扑翅膀,快速奔跑...");
}
public void say() {
super.fly();//*调用父类被覆盖的方法**
fly();//*调用本类中的方法**
}
}
/**
* 有参数构造函数,调用父类有参数构造函数
* @param name
* @param age
*/
public Person(String name,int age){
super(name, age);
}
/**
* 无参数构造函数,调用父类无参数构造函数
*/
public Person(){
super();
}
抽象类和抽象方法
抽象类
抽象类:就是用abstract修饰的类。
抽象类作用:就是用来装抽象方法的。
语法:
命名一般类名AbstractXxx
修饰符 abstract class AbstractXxx{
抽象方法:修饰符 abstract 返回值类型 方法名(...);
}
抽象类的使用场景: 一般作为业务父类(基类,模板类),且业务父类中,有的方法需要所有子类强制重写。
代码示例:
public class Circle extends AbstractGraph {
private double r;
public Circle() {
}
public Circle(double r) {
this.r = r;
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
@Override
public double getArea() {
return Math.PI * r * r;
}
}
/**
* 矩形
*/
public class Ractangle extends AbstractGraph {
private double height;
private double width;
public Ractangle() {
}
public Ractangle(double height, double width) {
super();
this.height = height;
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
@Override
public double getArea() {
return height * width;
}
}
测试代码:
/**
* 抽象类测试练习
*/
public class GraphTest {
public static void main(String[] args) {
//创建 子类对象
Circle circle = new Circle(5);
Ractangle ractangle = new Ractangle(3,5);
//调用父类继承过来的方法
double circleArea = circle.getArea();
double ractangleArea = ractangle.getArea();
System.out.println("圆形面积:"+circleArea);
System.out.println("矩形面积:"+ractangleArea);
// new AbstractGraph();//抽象类不能创建对象
}
}
抽象方法
抽象方法引入(代码示例):
/**
* 图形类(抽象类)装抽象方法的只能是抽象类
*/
public abstract class AbstractGraph {
/**
* 获取面积方法:由于每一个图形类的子类获取面积的方法都是不同的,所以,为了保证业务的合理性,
* 必须强制要求每一个子类都要重写该方法,通过抽象方法这种语法结构实现强制重写。
* @return
*/
public abstract double getArea();
}
Object类
Obj类引入
所有对象(包括数组)都可以调用到Object中的方法;
Obj类中方法
-
int hashCode() 返回对象的哈希码值。
-
boolean equals(Object obj) 根据实际业务,判断两个对象是不是“相等”,不是直接判断==
判断当前对象和obj参数是否"相等",要比较什么类型的对象就用重写其对应类型的equals方法
例如:
两个学生,我们认为姓名和电话号码相同就是同一个人,就用重写学生类的equals方法
两个教师,我们认为身份证号相同就是同一个人,就用重写教师类的equals方法
-
String toString() 返回对象的字符串表示形式。如果需要打印对象的制定格式,则需要重写当前对象所对 应类的toString方法即可
-
Class getClass() 返回此 Object的运行时类,即当前对象所对应的字节码文件
toString方法
equals方法
如下需求:两个学生,我们认为姓名和电话号码相同就是同一个人,就用重写学生类的equals方法
equals比较结果是:false 为什么呢?
代码示例:
public boolean equals(Student stu) {
//需求:两个学生,我们认为姓名和电话号码相同就是同一个人,就用重写学生类的equals方法
//要比较两个引用类型的值,就用该引用类型的equals方法,这里this.name是String的equals方法。并且String的equals方法已经重写了
if (this.name.equals(stu.name) && this.phoneNumber.equals(stu.phoneNumber)) {
return true;
}
return false;
}
重写后代码示例:
/**
* 学生类
*/
public class Student {
private String name;
private String phoneNumber;
int age;
public Student() {
}
public Student(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
/**
* 需求:希望打印对象的时候是指定格式:[隔壁老王,9969] [name的值,phoneNumber的值]就需要重写当前Student类的toSting方法
*/
@Override
public String toString() {
return "[" + name + "," + phoneNumber + "]";
}
public boolean equals(Student stu) {
//需求:两个学生,我们认为姓名和电话号码相同就是同一个人,就用重写学生类的equals方法
//要比较两个引用类型的值,就用该引用类型的equals方法,这里this.name是String的equals方法。并且String的equals方法已经重写了
if (this.name.equals(stu.name) && this.phoneNumber.equals(stu.phoneNumber)) {
return true;
}
return false;
}
}
测试代码:
public class StudentTest {
public static void main(String[] args) {
Student stu1 = new Student("隔壁老王","9969");
Student stu2 = new Student("隔壁老王","9969");
//1. 调用Object继承过来的hashCode方法
System.out.println("stu1的哈希值:"+stu1.hashCode());//366712642
System.out.println("stu2的哈希值:"+stu2.hashCode());//1829164700
//2. 打印对象是地址:特点(全限定包名+@+对象的哈希码的十六进制)
//需求:希望打印对象的时候是指定格式:[隔壁老王,9969] [name的值,phoneNumber的值]就需要重写当前Student类的toSting方法
System.out.println(stu1);//cn.itsource.object.Student@15db9742
System.out.println(stu2);//cn.itsource.object.Student@6d06d69c
//3. boolean equals(Object obj) 根据实际业务,判断两个对象是不是“相等”,不是直接判断==
//需求:两个学生,我们认为姓名和电话号码相同就是同一个人,就用重写学生类的equals方法
System.out.println(stu1.equals(stu2));//判断stu1对象是否和stu2对象相等。如果相等则是true,否则是false
//4. Class getClass() 返回此 Object的运行时类,即当前对象所对应的字节码文件 (反射最常用)字节码文件用==比较(了解)
Class<? extends Student> clazz = stu1.getClass();
System.out.println(clazz);//class cn.itsource.object.Student
Class<? extends Student> clazz2 = stu2.getClass();
System.out.println(clazz2);//class cn.itsource.object.Student
//字节码文件是否相等用==判断
System.out.println(clazz == clazz2);//true
}
}
== 和 equals区别(重点)
== :
比较基本数据类型: 比较的就是值是否相等;
比较引用数据类型: 比较的是对象的地址是否相等
equals 只能用于引用类型:
根据实际业务比较两个对象是否相等。默认是不重写是==比较。在实际开发中,我们一般比较对象都是通过对象的属性值进行比较(一般比较对象的地址没有多大用处),所以我们会覆写Object中的此方法,把自己的判断机制写在方法里面;
==与equals的区别面试被提问概率很大,需要理解并记住。笔者面试面试经验较多,小,中,大厂均有过面试经历。坚持每日分享全栈知识,与大家共同进步。