继承
类是对对象的抽象,继承是对某一批类的抽象,从而实现对现实世界更好的建模。
提高代码的复用性!
extands的意思是“扩展”。子类是父类的扩展
不同的叫法:超类、父类、基类、子类、派生类
如何使用继承:
①编写父类 ②编写子类,继承父类
不能被继承的父类成员:
①不能直接访问private成员
②子类与父类不在同包, 使用默认访问权限的成员
③构造方法
多重继承关系的初始化顺序:父类属性->父类构造方法->子类属性->子类构造方法
小结:
– 通过继承可以简化类的定义,实现代码的重用
– 子类继承父类的成员变量和成员方法,但不继承父类的构造方法
– java中只有单继承 ,没有像c++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。就像我们现实中,如果你有多个父母亲, 那是一个多么混乱的世界啊。多继承,就是为了实现代码的复用性,却引入 了复杂性,使得系统类之间的关系混乱。
– java中的多继承,可以通过接口来实现
– 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object
package com.petrel.extend;
public class Pet {
String name;
int age;
String tender;
public Pet(){
}
public Pet(String name,int age,String tender){
this.name = name;
this.age = age;
this.tender = tender;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setTender(String tender) {
this.tender = tender;
}
public String getTender() {
return tender;
}
public void play(){
System.out.println("Pet中的玩");
}
@Override
//toString的用法 如果这里没有这个代码,运行结果是:com.petrel.extend.Pet@4554617c
public String toString(){
return "my name is "+this.name+" . my age is "+this.age+" . my gender is "+this.tender;
}
}
------------
package com.petrel.extend;
public class dog extends Pet {
private String color;
public dog(){
}
public dog(String color,String name,int age,String tender){
//当super在构造方法中使用的话,会默认调用父类的构造方法 注意的点:super一定要放在第一行
super(name,age,tender);
this.color = color;
}
public void setColor(String color) {
this.color = color;
}
public String getColor(){
return color;
}
@Override
public void play(){
//super.play();
System.out.println("dog中的玩");
}
@Override
//父类的值不能满足子类的需要 就只能自己改写
public String toString() {
return super.toString()+" . my Color is "+this.color;
}
}
------------
package com.petrel.extend;
public class penguin extends Pet{
private String size;
public penguin(){
}
public penguin(String size,String name,int age,String tender){
super(name,age,tender);
this.size = size;
}
public void setSize(String size){
this.size = size;
}
public String getSize(){
return size;
}
}
------------
/**
* 继承:
* extands扩展,子类是父类的扩展
* 1.java中是单继承,不可以有多个父类,不然无法觉得该继承谁
* 2.父类:超类
* 子类:基类、派生类
* 3.父类中的属性和方法都可以在子类中进行(前提是非私有属性和非私有方法)
*
* 总结:
* 1.在创建子类对象的时候一定会优先创建父类对象
* 2.所有的java类都具备同一个老祖宗类,称之为Object,是所有类的根类
*
*/
package com.petrel.extend;
public class PetTest {
//String color,String name,int age,String tender
public static void main(String[] args) {
dog a = new dog();
a.setColor("白色");
a.setName("皮皮");
a.setAge(12);
a.setTender("雌");
penguin b = new penguin();
b.setName("小企鹅");
b.setSize("小");
System.out.println("狗狗的名字:"+a.getName()+" 年龄:"+a.getAge()+" 性别:"+a.getTender()+" 颜色:"+a.getColor());
System.out.println("企鹅的名字:"+b.getName()+" 体形:"+b.getSize());
a.play();
System.out.println("重写的运行结果:");
Pet pet = new Pet();
System.out.println(pet);
dog c = new dog();
System.out.println(c);
}
}
super关键字
super是直接父类对象的引用。
可以通过super来访问父类中被子类覆盖的方法或属性。
普通方法:没有顺序限制。可以随便调用。
构造函数中:任何类的构造函数中,若是构造函数的第一行代码没有显式的调用super(…);那么Java默认都会调用super();作为父类的初始化函数。 所以你这里的super();加不加都无所谓。
子类访问父类成员
– 访问父类构造方法
super();
super(name);
– 访问父类属性
super.name;
– 访问父类方法
super.print();
小结:
super关键字来访问父类的成员
super只能出现在子类的方法和构造方法中
super调用构造方法时,只能是第一句 super和this不能同时出现在构造方法中
super不能访问父类的private成员
super和this都不能再static方法中
// super关键字
// super是直接父类对象的引用(通俗一点讲就是不可以继承爷爷辈)
// 用途:
// 1.可以通过super来访问父类中被子类覆盖的方法或属性,见下面代码中的a.play(); 运行出来调用的是子类中的方法,如果想调用父类中的play方法则在子类的play方法中加上super.play();
// 2.当super在普通方法中使用的话,可以任意位置编写,只是输出顺序的不同
super.play();
System.out.println("dog中的玩");
// 输出:Pet中的玩
// dog中的玩
System.out.println("dog中的玩");
super.play();
// 输出:dog中的玩
// Pet中的玩
// 3.当super在构造方法中使用的话,会默认调用父类的构造方法
比如super(name,age,tender);
注意的点:super一定要放在第一行
// 4.在构造方法中super关键字和this关键字不能同时出现
可以:super(name,age,tender);
this.color = color; //这里不是构造方法,只是一个普通的属性值
但是不可以:super(name,age,tender);
this(); //这个好像是指向无参的构造方法
// 5.父类中的私有的属性和方法都不能被调用,包括构造方法
// 6.子类的构造方法中都会默认使用super关键字调用父类的无参构造方法(原因和存储有关)
// 在定义类的时候,无论是否自定义了其他构造方法,最好将无参构造方法写上
// 7.如果构造方法中显式的指定了super的构造方法,那么无参的构造方法就不会被调用
重写
在子类中可以根据需要对从基类中继承来的方法进行重写。
重写方法必须和被重写方法具有相同方法名称、参数列表和返回类型。
重写方法不能使用比被重写方法更严格的访问权限。(由于多态)
构造方法不能被继承, 因此不能重写
方法重写的规则
– 方法名相同
– 参数列表相同
– 返回值类型相同戒者是其子类;
– 访问权限不能严于父类
/* 重写:@Override
* 必须要存在继承关系,当父类中的方法无法满足子类需求的时候可以选择使用重写的方式
* 注意:
* 1.重写表示的是子类覆盖父类的方法,当覆盖之后,调用同样的方法的时候会优先调用子类
* 2.重写的方法名称,返回值类型,参数列表必须跟父类一致
* 3.子类重写的方法不允许比父类的方法具备更小的访问权限
* 父类 public 子类 public
* 父类 protected 子类 public protected
* 父类 default 子类 public protected default
*
* 父类的静态方法子类可以调用,但不能重写
*/
抽象
Java中使用抽象类,限制实例化
public abstract class Pet {
}
抽象方法
– 抽象方法必须在抽象类里
– 抽象方法必须在子类中被实现,除非子类是抽象类
public abstract void print(); //没有方法体
package com.petrel.Abstract;
/**
* java中的对象是对现实世界的具象化,但是在现实世界中,某些类并不具备实例化的意义,因此可以定义为抽象类
*
* 抽象类:
* 1.创建抽象类的时候需要添加abstract的关键字
* 2.不能进行实例化,也就是不能new对象
* 3.抽象类中的某些方法需要子类进行更丰富的实现,父类实现没有意义,此时可以将抽象类中的方法
* 定义为抽象方法,没有具体的实现,只包含方法名称,返回值,参数列表,访问修饰符
* 4.使用abstract关键字修饰的方法叫作抽象方法,可以不写方法的实现
* 5.子类在继承抽象父类的时候,必须要将父类中的抽象方法进行实现或者将子类也定义为抽象类
* 6.有抽象方法的一定是抽象类,但是抽象类中不一定包含抽象方法
*/
public class AbstractTest {
public static void main(String[] args) {
//Pet pet = new Pet(); 这里会报错Pet中加了abstract关键字 所以Pet不能被实例化
Dog dog = new Dog();
dog.print();
dog.play();
}
}
------------
package com.petrel.Abstract;
public abstract class Pet {
//这个宠物没必要打印,所以这个print方法实现没有意义
// public void print(){
//
// }
//使用abstract关键字修饰的方法叫作抽象方法,可以不写方法的实现
public abstract void print();
public void play(){
System.out.println("paly....");
}
}
------------
package com.petrel.Abstract;
public class Dog extends Pet {
private String gender;
//5.子类在继承抽象父类的时候,必须要将父类中的抽象方法进行实现或者将子类也定义为抽象类
//不写这里会报错 因为父类里面定义了一个抽象方法 当子类进行实现的时候必须把父类里面的抽象方法进行实现
@Override
public void print() {
System.out.println("Dog print");
}
}
final用法
package com.petrel.finals;
/**
* final的使用:
* final可以修饰变量:表示变量的值不可变
* final可以修饰方法:表示方法不可以被重写
* final可以修饰类:表示类不可以被继承
* public final class finaDome {}这样写的话
* public class finaSubClass extends finaDome{}这个继承就会报错
*/
public class finaDome {
public final void test(){
System.out.println("final test");
}
//final可以修饰变量:表示变量的值不可变
public static final int age = 10;
public static void main(String[] args) {
// age = 20; 这里的变量不可以修改
}
}
------------
package com.petrel.finals;
public class finaSubClass extends finaDome{
/*
//final修饰方法:方法不可以被重写
@Override
public final void test(){
}*/
}
对象的比较
等于:
– 比较两基本类型变量的值是否相等
– 比较两个引用类型的值即内存地址是否相等,即是否指向同一对象。
equals() :
– 两对象的内容是否一致
示例
– object1.equals(object2) 如:p1.equals(p2)
比较所指对象的内容是否一样
是比较两个对象,而非两个基本数据类型的变量
– object1 == object2 如:p1==p2
比较p1和p2的值即内存地址是否相等,即是否是指向同一对象。
自定义类须重写equals(),否则其对象比较结果总是false。
Object类
Object类是所有Java类的根基类
重写:toString方法:
默认返回:包名+类名+@+哈希码
package com.petrel.ObjectDome;
/**
* Object类是所有类的父类
*
* shift+shift 搜索Object
*
*native:本地、内核
*
* getclass
* 反射:获取私有属性、破坏了封装
*
* hashCode:计算哈希值
*
* equals:比较属性值
*
* clone:克隆一个一模一样的值
*
* toString:return getClass().getName() + "@" + Integer.toHexString(hashCode());最后是地址
*
* notify、wait:线程的唤醒和等待
*
* finalize:回收前判断对象是否还有引用,有引用就不能回收,JVM调用
*/
public class a {
/**
* 重新实现hashCode方法
* generator->Override Methods->hashCode()
* @return
*/
@Override
public int hashCode() {
return super.hashCode();
}
}
package com.petrel.ObjectDome;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public static void main(String[] args) {
Student s1 = new Student("zhangsan",12);
Student s2 = new Student("zhangsan",12);
System.out.println(s1==s2); //比较的是地址
System.out.println(s1.equals(s2)); //比较的是属性
}
}
练习
package com.petrel.RentCar;
public abstract class MotoVehicle {
private int no;
private String brand;
public abstract int calcRent(int day);
public MotoVehicle(){
}
public MotoVehicle(int no,String brand){
this.no = no;
this.brand = brand;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
------------
package com.petrel.RentCar;
public class Bus extends MotoVehicle {
private int seatcount;
public Bus(){
}
public Bus(int no,String brand,int seatcount) {
super(no, brand);
this.seatcount = seatcount;
}
public int getSeatcount() {
return seatcount;
}
public void setSeatcount(int seatcount) {
this.seatcount = seatcount;
}
@Override
public int calcRent(int day) {
if(seatcount>16){
return 1500*day;
}else{
return 800*day;
}
}
}
------------
package com.petrel.RentCar;
public class Car extends MotoVehicle {
private String type;
public Car(){
}
public Car(String type){
this.type = type;
}
public Car(int no,String brand,String type) {
super(no, brand);
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public int calcRent(int day) {
if (type.equals("0")) {
return 600 * day;
} else if (type.equals("1")) {
return 500 * day;
} else if (type.equals("2")) {
return 300 * day;
} else {
System.out.println("类型不匹配");
return 0;
}
}
}
------------
package com.petrel.RentCar;
public class Track extends MotoVehicle {
private int weight;
public Track(){
}
public Track(int no,String brand,int weight){
super(no,brand);
this.weight = weight;
}
@Override
public int calcRent(int day) {
return 50*day*weight;
}
}
------------
package com.petrel.RentCar;
public class TestMotoVehicle {
public static void main(String[] args) {
//MotoVehicle moto = new MotoVehicle(); 报错了,原因:抽象中可以有构造方法,但不能实例化
/* Car car = new Car(1,"宝马","1");
System.out.println("轿车的租金是:"+car.calcRent(5));
Bus bus = new Bus(2,"金龙",20);
System.out.println("客车的租金是:"+bus.calcRent(5));*/
MotoVehicle[] moto = new MotoVehicle[5];
moto[0] = new Car(1,"宝马","1");
moto[1] = new Car(1,"宝马","1");
moto[2] = new Car(2,"别克","2");
moto[3] = new Bus(3,"金龙",34);
moto[4] = new Track(4,"解放",50);
int totalMoney = calcTotal(moto);
System.out.println("总租金:"+totalMoney);
}
public static int calcTotal(MotoVehicle[] moto){
int totalMoney = 0;
for (int i = 0;i<moto.length;i++){
totalMoney+=moto[i].calcRent(5);
}
return totalMoney;
}
}