JavaSE-抽象类和接口

1.Object类 

Object类是所有类的父类,所有类都默认继承Object类,所以任何类都可以用Object类用来接收

 1.1获取对象信息

public class Main {
class  Person{
     public  String name;
    public   int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override//重写toString方法
    public String toString() {
        return  this.name + " " + this.age;
    }
}
 public static void main(String[] args) {
        {
            int a=1;
            int b=2;
            int c=3;
        }
        Object obj1 = new Person("RRR",32);//接受类
        System.out.println(obj1.toString());输出信息
    }
}
}
//运行结果
//RRR 32

 1.2 对象比较-equals

在Java中,用equals比较时,基本引用类型则比较变量值是否相同,引用类型则是比较变量地址是否相同,如果要比较对象内容,一定要重写equals方法。

如下图:

    public static void main(String[] args) {

            int a1=1;
            int b1=2;
            int c1=3;
//        System.out.println(Objects.equals(a1, b1));
//        Object obj1 = new Person("RRR",32);
//        System.out.println(obj1.toString().equals("RRR 32"));
        Object ME = new Person("刘佳",18);
        Person other =new Person("刘佳",18);
        Person RER = new Person("Ewew",312);
        System.out.println(other.equals(other));
        System.out.println(ME.equals(other));
        System.out.println(other.equals(ME));
    }
}
//true
//false
//false
             //以下在类中重写之后,即可得到3个true
//    @Override
//    public boolean equals(Object obj) {
//        if (obj == null){
//            return false;}
//        if (this == obj)
//        {   return true;}
//        if(!(obj instanceof Person)) {
//            return false;
//        }
//        Person other = (Person) obj;
//        return this.name.equals(other.name) && this.age == other.age;
//    }

 可以看出来,如果不重写类里面的equals方法,是无法比较类的内容的,只有重写之后,才能比较其内容,否则比较的是变量地址。就是false

1.3hashcode方法

hashCode这个方法就是给出一个具体的对象位置,这个对象位置以16进制输出

hashCode底是用C/C++写的,我们不用太关注

如果我们不重写hashCode方法,两个相同的类存放的位置就不一样,重写之后,即两个存放位置一样,如下图:

 

  @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

在类中重写之后:

 

小结:1.hashcode方法用来确定对象在内存中存储的位置是否相同

2.事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

2. 抽象类

2.1 抽象类概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是不是所有的都是这样的,如果某一个类里面没有包含足够的信息来描述一个具体的对象,这样的类就是抽象类

 

如上图所示的植物类,就是一个抽象类 ,抽象类中存在抽象方法,它并没有实际的工作方法,只能依靠子类中的重写方法来实现具体的工作,也就是多态性,来实现

2.2抽象类语法

抽象类中被abstract修饰的方法叫做抽象方法,抽象方法不用给出具体的实现方法

// 抽象类:被abstract修饰的类
public abstract class Plant {
// 抽象方法:被abstract修饰的方法,没有方法体
abstract public void easd();
abstract void casd2();
// 抽象类也是类,也可以增加普通方法和属性
public double getLength(){
return area;
}
protected double colar; //颜色
}

 2.3 抽象类特性总结

  • 抽象类不能直接实例化对象
  • 抽象方法不能private的
  • 抽象方法不能被final和static所修饰的,因为抽象方法要重写
  • 抽象类必须被继承,并且子类要重写抽象方法,否则子类也是抽象类,必须也用abstract来修饰
  • 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
  • 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

抽象类可以防止父类被误用,在某些情况下,父类不小心被使用时,编译器不会报错,但如果父类是抽象类就不一样了,编译器及时提醒我们,充分利用编译器的校验机制,在开发过程中非常有意义的

 3.接口

3.1接口概念

Java 中,接口可以看成是:多个类的公共规范,是一种引用数据类型
并且实现接口的类中要重写接口中的抽象方法
public interface  Ishape{
    void draw();
}
//用一个类去实现接口,注意public修饰词,要分开
public class Test1 implements Ishape {
    public void draw() {
        System.out.println("draw");
    }
}

3.2 语法规则

public interface 接口名称{
// 抽象方法
public abstract void method1(); // public abstract 是固定搭配,可以不写
public void method2();
abstract void method3();
void method4();
// 注意:在接口中上述写法都是抽象方法,推荐使用第四种
}

3.3 接口使用

要有一个类来实现该接口,并实现该接口中的所有抽象方法,不然会报错

package comit.demo2;

public class Test1 implements Ishape {
    public void draw() {
        System.out.println("draw");
    }
    public void move() {
        System.out.println("move");
    }
}

 语法规则:

public class 类名称 implements 接口名称 {
// ...
}

3.4 接口特性

  •  接口类型是一种引用类型,但是不能直接new接口的对象
public class TestUSB {
public static void main ( String [] args ) {
USB usb = new USB ();
}
}

//java: comit.demo2.USB是抽象的; 无法实例化

  •  
    接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是public abstract,其他修饰符都会报错)
  •  接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
  •  重写接口中方法时,不能使用默认的访问权限

 

  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
  • 接口中不能有静态代码块和构造方法

public interface IShape {
// 编译失败
public IShape(){
}
{} // 编译失败
void draw();
void move();
}
  • 接口不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  • 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
  •  jdk8中:接口中还可以包含default方法。

 3.5 实现多个接口

Java 中,类和类之间是单继承的,一个类只能有一个父类,即 Java 中不支持多继承 ,但是 一个类可以实现多个接 。下面通过代码解释

 

注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类

 3.6 接口间的继承

Java 中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。用接口可以达到多继承的目的。

 

 接口间的继承相当于把多个接口合并在一起.

 3.7 接口使用实例

3.7.1对象数组排序

class Person implements Comparable {
    private String name;
    private int score;

    public Person(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "[name=" + name + ", score=" + score + "]";
    }

    @Override
    public int compareTo(Object o) {
        Person p = (Person) o;
        if (this.score > p.score) {
            return -1;
        } else if (this.score < p.score) {
            return 1;
        }else {
            return 0;
        }
    }
}

public class Test1{
       public static void main(String[] args) {
           Person[] stu =new Person[]{
                   new Person("231",78),
                   new Person("231",86),
                   new Person("231",97),
           };
           Arrays.sort(stu);
           System.out.println(Arrays.toString(stu));
       }
}

 运行结果:

  sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.

利用Comparable可以实现类的冒泡排序,前提是必须重写CompareTo方法

    public static void  BubbleSort(Comparable[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = 0; j < a.length - i - 1; j++) {
                if (a[j].compareTo(a[j+1]) < 0) {
                    Comparable c = a[j];
                    a[j] = a[j+1];
                    a[j+1] = c;
                }
            }
        }
    }

3.8 Clonable 接口和深拷贝

Clonable是一个Java内置的接口,非常有用

Object 类中存在一个 clone 方法 , 调用这个方法可以创建一个对象的 " 拷贝 ". 但是要想合法调用 clone 方法 , 必须要先实现 Clonable 接口 , 否则就会抛出 CloneNotSupportedException 异常

Clonable是一个空接口!!!它的作用就是标记当前类是可以被克隆的

package demo3;
public class Student implements Cloneable {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    protected Object clone()
            throws CloneNotSupportedException {  //解决异常
            return super.clone();
        }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}
class main {
    public static void main(String[] args)  //注意这里没有花括号
        throws CloneNotSupportedException {
            Student s1 = new Student("刘佳", 18);
            Student s2 = (Student) s1.clone();
        System.out.println(s1);
        System.out.println(s2);
    }
    }

 

 但两者的地址是不一样的:

假设每个学生类中还有一个钱包类,通过clone,我们只是拷贝了Student对象。但是Student对象中的Money对象,并没有拷贝。通过s2这个引用修改了m的值后,s1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝,如下代码:

public class Student implements Cloneable {
    private String name;
    private int age;
    Money money;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        money = new Money();
    }
    @Override
    protected Object clone()
            throws CloneNotSupportedException {
            return super.clone();
        }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", money=" + money +
                '}';
    }

class main {
    public static void main(String[] args)
        throws CloneNotSupportedException {
            Student s1 = new Student("刘佳", 18);
            Student s2 = (Student) s1.clone();
        System.out.println("修改前");
        System.out.println(s1.money.money);
        System.out.println(s2.money.money);
        s2.money.money=19.9;
        System.out.println("修改后");
        System.out.println(s1.money.money);
        System.out.println(s2.money.money);
    }
    }

如上就是发生了浅拷贝,只是将对象的内容完完全全复制了一份到另一个空间

对上进行深拷贝,其实就是将学生中的money再拷贝一份,如下代码,

package demo3;
class Money implements Cloneable{
    public  double money=9.9;
    @Override
    protected Object clone()
            throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Student implements Cloneable {
    private String name;
    private int age;
    Money money;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        money = new Money();
    }
    @Override
    protected Object clone()
            throws CloneNotSupportedException {
           Student student = (Student) super.clone();
           student.money = (Money)this.money.clone();//克隆一份新的money
           return student;
        }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", money=" + money +
                '}';
    }
}
class main {
    public static void main(String[] args)
        throws CloneNotSupportedException {
            Student s1 = new Student("刘佳", 18);
            Student s2 = (Student) s1.clone();
        System.out.println("修改前");
        System.out.println(s1.money.money);
        System.out.println(s2.money.money);
        s2.money.money=187.9;
        System.out.println("修改后");
        System.out.println(s1.money.money);
        System.out.println(s2.money.money);
    }
    }

运行结果: 

3.9 抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题).

 核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法

假设一个动物类中有皮毛颜色等属性,这些属性在其子类中也存在,也就注定了动物类无法称为接口.只能作为抽象类

抽象类存在的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类.
万一不小心创建了 Animal 的实例, 编译器会及时提醒我们.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值