1.抽象类概念
并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
2.抽象类语法
3.抽象类特性
(1)抽象类使用abstract修饰类
(2)抽象类当中可以包含普通类所能包含的成员
(3)抽象类和普通类不一样的是,抽象类当中可以包含抽象方法
(4)抽象方法是使用abstract修饰的,这个方法没有具体的实现
(5)不能实例化抽象类new
(6)抽象类最大的存在意义就是被继承
(7)如果一个普通类继承了一个抽象类,那么就必须重写它的抽象方法
(8)如果一个抽象类A继承了一个抽象类B,此时A当中 不需要重写B中的抽象方法。但是如果A再被普通类继承就需要重写了
(9)抽象类的权限不能是private,也就是要满足重写的条件
(10)final不可以,static也不行
(11)抽象类当中可以有构造方法,为了方便子类能够调用,用来初始化抽象类当中的成员
4.抽象类的作用
抽象类本身不能被实例化,要想使用,只能创建该抽象类的子类,然后让子类重写抽象类中的抽象方法
使用抽象类他就相当于多了一重编译器的校验
5.接口
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在Java中,接口可以看成:多个类的公共规范,是一种引用数据类型。
1.使用interface来修饰接口
2.接口当中的成员方法,不能有具体的实现
1.抽象方法:默认是public abstract的方法
2.在jdk1.8开始,可以有具体的方法,饭必须是由default修饰的
3.可以实现有一个静态方法。
3.成员变量默认是public static final修饰的
4.接口不能被实例化.
5.类和接口之间使用implements来实现一个或多个接口
interface ITest{ int size = 10;//public static final void draw1();//public abstract public abstract void draw(); default public void fun(){ System.out.println("默认方法"); } public static void fun1(){ } }
6.子类重写抽象方法,必须假设public
7.接口中不能有静态代码块和构造方法。
8.如果你不想实现接口的方法,那么就把这个类定义为抽象类。但是如果这个类被其他类继承,呢么必须重写。
9.一个类可以实现多个接口,使用implements用逗号隔开。【可以解决多继承的问题】
规范:
1.创建接口时,一般使用大写的字母i开头
2.接口命名一般使用形容词词性的单词
3.阿里编码规范中约定,接口中的方法和属性不要加任何修饰符号,保持代码的简洁性
int size = 10;//public static final void draw1();//public abstract
6.接口的实现
上节课的
package demo3; interface IShape{ void draw(); } //快捷键鼠标放到class这里,Alt+Enter class Rect implements IShape{ @Override public void draw() { System.out.println("矩形"); } } class Flower implements IShape{ @Override public void draw(){ System.out.println("花"); } } class Cycle implements IShape{ @Override public void draw() { System.out.println("圆"); } } public class Test2 { public static void drawMap(IShape ishape){ ishape.draw(); } public static void main(String[] args) { Rect rect = new Rect(); drawMap(rect); drawMap(new Flower()); drawMap(new Cycle()); } }
本节课的
package demo3; interface USB{ void openDevice(); void closeDevice(); } class Mouse implements USB{ @Override public void openDevice() { System.out.println("打开鼠标"); } @Override public void closeDevice() { System.out.println("关闭鼠标"); } public void click(){ System.out.println("鼠标点击"); } } class Keybroad implements USB{ @Override public void openDevice() { System.out.println("打开键盘"); } @Override public void closeDevice() { System.out.println("关闭键盘"); } public void input(){ System.out.println("键盘输入"); } } class Computer{ public void powerOn(){ System.out.println("打开电脑"); } public void powerOff(){ System.out.println("关闭笔记本"); } public void useDevise(USB usb){ usb.openDevice(); if(usb instanceof Mouse){ Mouse mouse = (Mouse) usb; mouse.click(); } else if (usb instanceof Keybroad) { Keybroad keybroad = (Keybroad) usb; keybroad.input(); } usb.closeDevice(); } } public class Test3 { public static void main(String[] args) { Computer computer = new Computer(); computer.powerOn(); computer.useDevise(new Mouse()); computer.useDevise(new Keybroad()); computer.powerOff(); } }
7.接口的特性
1.接口类型是一种引用类型,但是不能直接new接口的对象
2.接口中每一个方法都是public的抽象方法,即接口中的方法会被隐式的指定为public abstract(只能是public abstract,其他修饰符都会报错)
3.接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
4.重写接口中方法时,不能使用默认访问权限修饰
5.接口中可以含有变量,但是接口中的变量会被隐式指定为public static final变量
6.接口中不能有静态代码块和构造方法
7.接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
8.如果类没有实现接口中所有的抽象方法,则类必须设置为抽象类
9.jdk8中,接口还可以包含default方法
8.实现多个接口
一个类可以实现多个接口,使用implements用逗号隔开。(可以解决多继承的问题)
例子1:
interface A1{ void func(); } interface B1{ void func2(); } class C1 implements A1,B1{ @Override public void func() { } @Override public void func2() { } }
例子2:
package demo3; interface IFlying{ void flying(); } interface ISwimming{ void swimming(); } interface IRunning{ void running(); } class Animals{ public String name; public int age; public Animals(String name, int age) { this.name = name; this.age = age; } public void eat(){ System.out.println("吃饭"); } } class Dog extends Animals implements IRunning,ISwimming{ public Dog(String name,int age){ super(name,age); } @Override public void running() { System.out.println(name + "正在跑步"); } @Override public void swimming() { System.out.println(name + "正在游泳"); } @Override public void eat() { System.out.println(name + "正在吃狗粮"); } } class Bird extends Animals implements IFlying{ public Bird(String name,int age){ super(name, age); } @Override public void flying() { System.out.println(name + "正在飞"); } @Override public void eat() { System.out.println(name + "正在吃鸟粮"); } } class Duck extends Animals implements IRunning,ISwimming,IFlying{ public Duck(String name,int age){ super(name,age); } @Override public void flying() { System.out.println(name + "正在飞"); } @Override public void swimming() { System.out.println(name + "正在游泳"); } @Override public void running() { System.out.println(name + "正在跑"); } @Override public void eat() { System.out.println(name + "正在吃鸭子粮"); } } public class Test5 { public static void walk(IRunning iRunning){ iRunning.running(); } public static void fly(IFlying iFlying){ iFlying.flying(); } public static void func(Animals animals){ animals.eat(); } public static void main(String[] args) { /*Dog dog = new Dog("xiaozhang",5); dog.running(); dog.swimming();*/ walk(new Dog("hello",8)); walk(new Duck("hello1",4)); func(new Dog("11",1)); func(new Bird("12",1)); } }
继承表达了is-a的语义,而接口表达的含义是:具有xxx特性
这样设计的好处是让程序员忘记类型,有了接口之后,类的使用者就不必关注具体类型,而只关注某个类是否具有某种能力
9.接口与接口的继承
接口之间的继承就相当于一个拓展,就是把他们结合到了一起
接口与接口之间使用extends
interface D1 extends A1,B1{ void func3(); }
类和接口之间使用implements
class C1 implements A1,B1{ @Override public void func() { } @Override public void func2() { } }
10.抽象类和接口的区别
11.Object类
Object类是所有类的父类,我们自己写的类,就算没有显示的extends Object。默认继承的
package demo3; class Person{ } class Student{ } public class Test6 { public static void func(Object obj){ } public static void main(String[] args) { func(new Person()); func(new Student()); } }
Object类的两个重要的方法equals方法和hashcode方法
1.equals方法
public static void main(String[] args) { Person person = new Person("张三",18); Person person1 = new Person("张三",18); System.out.println(person.equals(person1)); }
得出的结果为false,因为在源码中是这样的
public boolean equals(Object obj) { return (this == obj); }
他比较的是引用变量中存储的地址,他们的地址不一样,那么我们想要让他们一样的话就需要给他们重写equals方法
class Person{ private String name; private int age; public Person(String name, int age){ this.age = age; this.name = name; } @Override public boolean equals(Object obj) {
if(obj == null){ return false; } if(this == obj){ return true; } //不是Person类对象,不是同种类型 if(!(obj instanceof Person)){ return false; } Person person = (Person) obj; if(this.name.equals(person.name)&&(this.age == person.age)){ return true; }else{ return false; } } } public class Test6 { public static void main(String[] args) { Person person = new Person("张三",18); Person person1 = new Person("张三",18); System.out.println(person.equals(person1)); } }
如果以后写了自定义类型,要注意重写equals方法
2.hashCode方法
hashCode方法用来确定对象在内存中存储的位置是否相同
事实上hashCode()在散列表中才有用,在其他情况下没用。在散列表中hashCode()的作用是获取对象的散列码,进而确定对象在散列表中的位置。
计算对象的位置
public static void main(String[] args) { Person person = new Person("张三",18); Person person1 = new Person("张三",18); System.out.println(person.equals(person1)); System.out.println(person.hashCode()); System.out.println(person1.hashCode()); }
编译结果就是
189568618
793589513
但是同名,同age为什么不一样呢
这时候就得重写hashCode方法
@Override public int hashCode() { return Objects.hash(name,age); } }
3.其实自己不用具体重写,直接右键Generate然后
然后一路点确认下来,编译器就自动给你写好了
作业一:
作业二:
下列关于Java抽象类的说法哪个正确?
某个抽象类的父类是抽象类,则这个子类必须 重载父类的所有抽象方法
抽象类和接口是同一回事
可以用抽象类直接去实例化创建对象)(抽象类和接口都不能实例化)
一个类只能继承一个抽象类
作业三:
java接口的修饰符可以为()
private
protected
final
abstract
作业四:
那些方法是Object类中的方法(都是)
clone(),toString(),wait(),finalize()
12.自己写的类排序问题(写的第一个接口 关于Compare)
1.报错的
import java.util.Arrays; import java.util.Collection; import java.util.Comparator; class Student implements { public int age; public String name; public Student( String name,int age) { this.age = age; this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; } public class Test { public static void main(String[] args) { Student[] students = new Student[3]; students[0] = new Student("fjq",5); students[1] = new Student("fjq1",15); students[2] = new Student("fjq2",25); Arrays.sort(students); System.out.println(Arrays.toString(students)); } }
2.按年龄排
这个时候就会报错,他必须得
class Student implements Comparable<Student> { public int age; public String name; public Student( String name,int age) { this.age = age; this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; } /** * @param o the object to be compared. * @return */ @Override public int compareTo(Student o) { if(this.age - o.age > 0){ return 1; } else if (this.age - o.age < 0) { return -1; }else{ return 0; } } } public class Test { public static void main1(String[] args) { Student[] students = new Student[3]; students[0] = new Student("fjq",5); students[1] = new Student("fjq1",15); students[2] = new Student("fjq2",25); Arrays.sort(students); System.out.println(Arrays.toString(students)); }
public static void main(String[] args) { Student student1 = new Student("fjq",15); Student student2 = new Student("zxl",12); if(student1.compareTo(student2) > 0){ System.out.println("student1 > student2"); }else{ System.out.println("student1 < student2"); } }
}
写这个方法,告诉程序我这个类要怎么进行排序
总结:如果我们以后自定义的类型,一定要记住,如果比较大写,那么必须要让这个类具备可以比较的功能,此时可以选择实现接口:Comparable
此时我们项目要更改需求,我现在要根据我的名字来进行排序了
3.按名字排
class NameComparator implements Comparator<Student>{ /** * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @return */ @Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); } } public class Test { public static void main(String[] args) { Student[] students = new Student[3]; students[0] = new Student("gjq",5); students[1] = new Student("fjq1",15); students[2] = new Student("hjq2",25); NameComparator nameComparator = new NameComparator(); Arrays.sort(students,nameComparator); System.out.println(Arrays.toString(students)); }
comparable对类的侵入性非常强,comparator侵入性比较弱,他们都是比较器。
compareto他返回的是整数类型,而equals返回的是布尔类型
4.年龄名字共同实现
class AgeComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.age - o2.age; } } class NameComparator implements Comparator<Student>{ /** * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @return */ @Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); } } public class Test { public static void main(String[] args) { Student student1 = new Student("fjq",15); Student student2 = new Student("zxl",12); AgeComparator ageComparator = new AgeComparator(); if((ageComparator.compare(student1,student2)) > 0){ System.out.println("student1 > student2"); }else{ System.out.println("student1 < student2"); } } public static void mai3n(String[] args) { Student[] students = new Student[3]; students[0] = new Student("gjq",5); students[1] = new Student("fjq1",15); students[2] = new Student("hjq2",25); NameComparator nameComparator = new NameComparator(); Arrays.sort(students,nameComparator); System.out.println(Arrays.toString(students)); }
5.冒泡排序排
public class Test { public static void bubbleSort(Comparable[] array){ for (int i = 0; i < array.length-1; i++) { for (int j = 0; j < array.length-1-i; j++) { if (array[j].compareTo(array[j + 1])> 0){ Comparable tmp = array[j]; array[j] = array[j + 1]; array[j + 1] = tmp; } } } } public static void main(String[] args) { Student[] students = new Student[3]; students[0] = new Student("gjq",5); students[1] = new Student("fjq1",15); students[2] = new Student("hjq2",25); bubbleSort(students); System.out.println(Arrays.toString(students)); }
13.clone接口
class Person{ public int id; @Override public String toString() { return "Person{" + "id=" + id + '}'; } } public class Test2 { public static void main(String[] args) { Person person = new Person(); Person person1 = person.clone(); } }
此时这个clone是用不了的,必须implements一个Cloneable接口
package demo4; class Person implements Cloneable{ public int id; /** * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "id=" + id + '}'; } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException{ Person person = new Person(); Person person1 = (Person) person.clone(); } }
但是是这个Cloneable接口是空接口,他只是代表我这个类现在可以进行克隆了
ctrl点住,看这个clone的源码,它是由protected修饰的
protected native Object clone() throws CloneNotSupportedException;
不同包 当中就需要通过super去访问
所以此时的当前类当中就必须重写clone方法
-----------------------------------------------------------------------------------------------------------------------
总结:一个对象想被克隆
1.实现Cloneable接口
implements Cloneable
2.重写克隆方法
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
3.声明异常
public class Test2 { public static void main(String[] args) throws CloneNotSupportedException{ Person person = new Person(); Person person1 = (Person) person.clone(); } }
14.深拷贝和浅拷贝
1.浅拷贝
结果
person--199
person1--199
package demo4; class Money{ public double m = 12.5; } class Person implements Cloneable{ public int id; public Money money = new Money(); /** * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "id=" + id + '}'; } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException{ Person person = new Person(); Person person = (Person) person.clone(); person1.money.m = 199; System.out.println("person1--" + person1.money.m); System.out.println("person --" + person.money.m); } }
2.深拷贝
结果
person --12.5
person1--199.0
lass Money implements Cloneable{ public double m = 12.5; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable{ public int id; public Money money = new Money(); /** * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { //return super.clone(); Person tmp = (Person)super.clone();//克隆person tmp.money = (Money) this.money.clone();//克隆money return tmp; } @Override public String toString() { return "Person{" + "id=" + id + '}'; } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException{ Person person = new Person(); Person person1 = (Person) person.clone(); person1.money.m = 199; System.out.println("person --" + person.money.m); System.out.println("person1--" + person1.money.m); } }