抽象类
1. 抽象类的概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类————即方法里面没有内容,只有一个空壳子。
2.抽象类的知识点
1、被abstract修饰的类就是抽象类 2、被abstract修饰的方法就是抽象方法 3、抽象类不能被实例化,就不能被 new 4、抽象类里面的成员和普通类里面的成员一样,只不过不能被实例化 5、当一个普通的类继承这个抽象类之后,那么这个普通类,必须重写这个抽象类中的所有方法 6、抽象类存在的最大的意义就是被继承 7、抽象类也可以发生向上转型,进一步发生多态 8、当一个抽象类A 继承了 抽象类B 时,就像类A 就不用重写抽象类B中的方法 9、当一个普通类 继承了第8条的 A时,此时就得重写A 和 B中所有的抽象方法 10、final不能修饰抽象方法,也不能修饰抽象类,因为被final修饰的一定不能被继承,而被abstract修饰的必须得继承 11、抽象方法也不能被private修饰,原因:抽象方法必须被重写,但是被private修饰后,子类都无法访问父类中的该方法 12、抽象方法不能被static修饰,原因:static修饰的静态类要是被重写,在调用时,也不能动态绑定到子类的方法,没有任何的意义 13、抽象类当中不一定有抽象方法,但是有抽象方法的类一定时抽象类
看一个代码:
abstract class Shape{
public abstract void draw();
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("?");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("?");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("🔺");
}
}
public class TestDemo {
public static void drawMap(Shape shape){
shape.draw();
}
public static void main(String[] args) {
Cycle cycle=new Cycle();
Rect rect =new Rect();
Triangle triangle=new Triangle();
drawMap(cycle);
drawMap(rect);
drawMap(triangle);
}
}
3. 抽象类的作用
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?
确实如此. 但是使用抽象类相当于多了一重编译器的校验. 使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.
很多语法存在的意义都是为了 “预防出错”, 例如我们曾经用过的 final 也是类似. 创建的变量用户不去修改, 不 就相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们. 充分利用编译器的校验, 在实际开发中是非常有意义的
接口
1. 接口的概念
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。 在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型
2. 接口的知识点
1、接口使用关键字 interface 来修饰 2、接口当中的成员方法,只能是抽象方法。所有的方法 默认都是public abstract 3、接口当中的成员变量默认是public static final 4、接口当中的方法,如果要实现,需要用 default 来修饰 5、接口当中的静态方法可以有具体的实现 6、接口不能进行实例化,即不能 new 7、一个普通的类,可以通过 implements 来实现这个接口 8、接口中不能有静态代码块和构造方法 9、接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class 10、如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类 11、jdk8中:接口中还可以包含default方法。 12、一个类,可以继承抽象类,同时实现多个接口。每个接口之间使用逗号分割 13、接口和类之间的的关系是implements。接口和接口之间关系是extends,意为拓展。 14、当接口C 拓展了 A,B时,如果有类 D implements C,则在D中必须重写A,B,C 中所有的方法。
代码示例:
class Animal{
public String name;
public int age;
public Animal(String name){
this.name=name;
}
public void est(){
System.out.println(this.name+"吃饭饭!");
}
}
interface IFlying{
void fly();
}
interface IRunning{
void run();
}
interface ISwimming{
void swim();
}
class Dog extends Animal implements IRunning,ISwimming{
public Dog(String name){
super(name);
}
@Override
public void run() {
System.out.println(this.name+"正在跑!");
}
@Override
public void swim() {
System.out.println(this.name+"正在游泳!");
}
}
class Cat extends Animal implements IRunning{
public Cat(String name){
super(name);
}
@Override
public void run() {
System.out.println(this.name+"正在跑!");
}
}
class Duck extends Animal implements ISwimming,IRunning,IFlying{
public Duck(String name){
super(name);
}
@Override
public void fly() {
System.out.println(this.name+"正在飞");
}
@Override
public void run() {
System.out.println(this.name+"正在跑");
}
@Override
public void swim() {
System.out.println(this.name+"正在游泳");
}
}
public class TestDemo {
public static void walk(IRunning iRunning){
iRunning.run();
}
public static void fly(IFlying iFlying){
iFlying.fly();
}public static void swim(ISwimming iSwimming){
iSwimming.swim();
}
public static void main(String[] args) {
swim(new Dog("wang"));
walk(new Cat("mimi"));
swim(new Duck("唐老鸭"));
}
}
3.三个比较重要的接口
3.1 comparable
在Java当中,如果引用类型比较大小,需要具备以下两个条件: 1.可以比较 2.重写了某个方法
class Student implements Comparable<Student>{
public String name;
public int age;
public double score;
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
@Override
public int compareTo(Student o) {
if(this.age>o.age){
return 1;
}else if(this.age==o.age){
return 0;
}else{
return -1;
}
}
}
public class TestDemo {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0]=new Student("zhangsan",98,78.9);
students[1]=new Student("lisi",18,18.9);
students[2]=new Student("zns",68,88.9);
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}
上面代码的不足之处在:对原始类的侵入性太强 下面,我们进行改进:
class Student{
public String name;
public int age;
public double score;
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
class AgeComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;
}
}
class StringComparator implements Comparator<Student>{
@Override
public int compare(Student o1,Student o2) {
return o1.name.compareTo(o2.name);
}
}
class ScoreComparator implements Comparator<Student>{
@Override
public int compare(Student o1,Student o2) {
return (int)(o1.score-o2.score);
}
}
public class TestDemo {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0]=new Student("zhangsan",98,78.9);
students[1]=new Student("lisi",18,18.9);
students[2]=new Student("wns",68,88.9);
AgeComparator ageComparator=new AgeComparator();
Arrays.sort(students,ageComparator);
System.out.println(Arrays.toString(students));
StringComparator stringComparator =new StringComparator();
Arrays.sort(students,stringComparator);
System.out.println(Arrays.toString(students));
ScoreComparator scoreComparator =new ScoreComparator();
Arrays.sort(students,scoreComparator);
System.out.println(Arrays.toString(students));
}
}
3.2Cloneable 接口和深拷贝
发生克隆的条件:
- 可以克隆
- 重写object克隆方法
class Person implements Cloneable{
public String id="1234";
@Override
public String toString() {
return "Person{" +
"id='" + id + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1=new Person();
Person person2=(Person)person1.clone();
}
}
代码分析: 图解代码功能:
上面的代码看似已经对拷贝进行了实现,但是如果一个类中有示例话的对象时,上述代码也就只能实现浅拷贝,就像下面的代码一样:
class Money{
int money=30;
}
class Person implements Cloneable{
public String id="1234";
Money m=new Money();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1=new Person();
Person person2=(Person)person1.clone();
System.out.println(person1.m.money);
System.out.println(person2.m.money);
System.out.println("==============");
person1.m.money=90;
System.out.println(person1.m.money);
System.out.println(person2.m.money);
}
}
运行结果: 图解代码: 上述代码只进行了浅拷贝,并没有对对象中的实例化对象进行拷贝,只能拷贝了它的地址,即person1.m.money和person2.m.money是同一个对象,下面我们将进行深拷贝:
class Money implements Cloneable{
public int money=30;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public String id="1234";
Money m=new Money();
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp=(Person)super.clone();
tmp.m=(Money)this.m.clone();
return tmp;
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1=new Person();
Person person2=(Person)person1.clone();
System.out.println(person1.m.money);
System.out.println(person2.m.money);
System.out.println("==============");
person1.m.money=90;
System.out.println(person1.m.money);
System.out.println(person2.m.money);
}
}
代码分析: 图解代码: 在上面的代码中,进行了深拷贝之后,即对 m 也进行了拷贝,所以修改person1.m.money时,person1.m.money并没有改变。
3.3 Object类
Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。即所有类的对象都可以使用Object的引用进行接收
3.3.1 对象比较equals方法——判断对象的内容是否一致
在Java中,==进行比较时:
- 如果==左右两侧是基本类型变量,比较的是变量中值是否相同
- 如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
- 如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的。
class Student{
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
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);
}
}
public class TestDemo {
public static void main(String[] args) {
Student student1=new Student("lisi",19);
Student student2=new Student("lisi",19);
System.out.println(student1.equals(student2));
}
}
运行结果:
代码分析:
3.3.2 hashcode方法——计算对象具体存在的位置
当两个对对象所指定的属性一致时,就认为她两位置一样,即hashcode的值一样
class Student{
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class TestDemo {
public static void main(String[] args) {
Student student1=new Student("lisi",19);
Student student2=new Student("lisi",19);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
}
}
运行结果:
|