目录
1.抽象类
1.1 抽象类的语法
被abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法
abstract class Draw {
public Draw() {
System.out.println("Draw的构造方法");
}
//抽象方法不能有主体
public abstract void draw();
public void func() {
System.out.println("Draw::func()");
}
}
抽象方法不可以有主体。
抽象类和其他类一样可以有自己的成员属性和方法,以及构造方法。
1.2 抽象类的特点
1.抽象类与普通类的区别就是:抽象类中可以有抽象方法(也可以没有)
2.抽象类不能直接实例化对象
public static void main(String[] args) {
//Draw是抽象类
Draw draw0 = new Draw(); //---Error---
//会报错
}
3.抽象方法不可以被private修饰符修饰,被final、static修饰的方法也不能成为抽象方法
abstract class Draw {
public Draw() {
System.out.println("Draw的构造方法");
}
//抽象方法不能有主体
public abstract void draw();
//private abstract void draw1(); ---Error---
//public final abstract void draw2(); ---Error---
//public static abstract void draw3(); ---Error---
public void func() {
System.out.println("Draw::func()");
}
}
4.当抽象类被继承后,子类必须要重写父类(抽象类) 的抽象方法,如果子类不想重写抽象方法,那么子类必须是抽象类,但是当子类再次被继承时,子类的子类必须重写所有的抽象方法。
比如:类A是抽象类,抽象类 类B继承了类A,类C继承了类B,那么类C中必须重写类A和类B中的所有抽象方法。
5.抽象类也有多态性
2.Object类
Object类是所有类的父类,所以,所有类都可以重写或直接调用Object类中的方法
2.1 equals方法
equals方法是比较两个变量是否相等,范围boolean类型
原码如下:
public boolean equals(Object obj) {
return (this == obj); // 使用引用中的地址直接来进行比较
}
如果要比较的是像int、char这种基本类型的数值,可以直接使用原码的equals方法
如果要比较两个引用的地址,也可以直接使用equals方法
但是如果比较的两个对象,那么就需要重写equals方法
class Person1 {
public String name;
public int age;
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Person1)) {
return false;
}
Person1 person = (Person1) obj;
if (this.name.equals(person.name) && this.age == person.age) {
return true;
}
return false;
}
}
public class Test {
public static void main(String[] args) {
Person1 person1 = new Person1("张三", 18);
Person1 person2 = new Person1("张三", 18);
//System.out.println(person1.equals(person2)); // 没重写equals方法前是 false
System.out.println(person1.equals(person2));//重写后是true
}
}
3.接口
3.1 接口的语法
1.被interface修饰的是接口
2.接口中的成员变量默认是public static final类型
3.接口中的方法默认是public abstract类型
interface USB {
//普通成员会默认为public static final类型
public static final int ret = 10;
int ret1 = 20;
public abstract void open();
void close();//默认public abstract类型
}
3.2 接口的使用及特性
1.接口与接口之间的使用时继承关系,接口可以继承另一个接口。
2.接口与类之间的使用要用 implements 实现关系,并且一个类可以同时接收多个接口。
3.类接收接口之后必须重写接口中的抽象方法,如果不想重写,那么类必须是抽象类。
4.接口不可以被实例化。
5.接口中的方法只能被 public abstract 修饰,且不能被实现,在 jdk1.8 及以后可以有 static 修饰或者被 default 修饰的方法且可以实现,除此之外,不可以被其他修饰符修饰。
6.接口中不能有静态代码块和构造方法
interface USB {
//普通成员会默认为public static final类型
public static final int ret = 10;
int ret1 = 20;
public abstract void open();//默认public abstract类型
void close();
public static void func() {
System.out.println("jdk1.8及以后 接口中可以有 static 方法");
}
default void fun() {
System.out.println("jdk1.8及以后 接口中可以有 default 修饰的方法");
}
}
interface USB1 {
}
/**
* 1.如果不想重写接口中的抽象类 必须被修饰成抽象类
* 但是如果有其他类继承了这个类 那么仍然需要重写这些方法
*/
abstract class A implements USB {
}
/**
* 1.重写的方法不能用默认的访问权限 因为重写后的范围要大于等于之前的范围
* 2.类和接口之间用 implements 来实现多个接口
*/
class Mouse implements USB,USB1 {
public void open() {
System.out.println("打开鼠标");
}
public void close() {
System.out.println("关闭鼠标");
}
public void use() {
System.out.println("使用鼠标");
}
}
3.3 Comparable接口和Comparator接口
3.3.1 Compapable接口
我们在进行自定义类型比较的时候,没办法直接通过简单的 大于、小于、等于 来判断,这时我们可以在类中添加一个Compapable接口,并重写里面的compareTo方法
在compareTo方法中自己去设置比较的条件,下面举一个例子
class Student implements Comparable<Student> {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
public static void main(String[] args) {
Student student1 = new Student("bit", 10);
Student student2 = new Student("hello", 40);
if (student1.compareTo(student2) > 0) {
System.out.println("student1 > student2");
} else {
System.out.println("student1 <= student2");
}
}
compareTo的返回是int类型,我们定义了一个Student类,里面有name和age属性,代码里面是用age的大小来做比较的条件,那么当我们想通name来做比较的条件就会变得很复杂,因为compareTo方法也叫被重写过了,这时就可以用到另一个接口Comparator。
3.3.2 Comparator接口
当我们需要对一个自定义类型用多种方式来进行比较大小时,就可以再定义一个新的类,让新的类去继承Comparator接口,然后去实现里面的compare方法(返回值也是int),来达到用多种方式比较自定义类型大小的目的。
实例如下:
class Student implements Comparable<Student> {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
class AgeComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student("bit", 10);
students[1] = new Student("hello", 40);
students[2] = new Student("abc", 30);
AgeComparator ageComparator = new AgeComparator();
Arrays.sort(students, ageComparator);
System.out.println(Arrays.toString(students));
NameComparator nameComparator = new NameComparator();
Arrays.sort(students, nameComparator);
System.out.println(Arrays.toString(students));
}
实例中分别用了两个类去实现Student类用name比较大小和用age比较大小,最后的结果大家可以自己去试一下。
3.4 Cloneable接口和深拷贝
当我们想将一个对象拷贝到另一个相同类型的对象里去时,需要调用Object类里的clone方法,但是要调用这个方法需要要先实现Cloneable接口,否则就会抛出 CloneNotSupportedException 异常。
举个例子:
class Money {
public double m = 12.5;
}
/**
* 调用Object类的clone方法 必须要接收Cloneable接口
* 并且要重写clone()方法
* 用protected修饰的 在不同包中访问 需要用super
*/
class Person implements Cloneable{
public int id;
public Money money = new Money();
/**
* 浅拷贝
* 浅拷贝是将这个类对象拷贝过去,但是其里面的组合对象不会再拷贝一份,而是指向同一个对象
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
'}';
}
}
public class Test3 {
public static void main(String[] args) throws CloneNotSupportedException{
Person person1 = new Person();
person1.id = 99;
Person person2 = (Person)person1.clone();
}
}
我们可以看到,在Person类中有一个组合对象money,当我们拷贝了person1给到person2后,money里面的数据并不会拷贝一份,而是两个Person类对象的money指向了同一块数据,当person1或者person2区修改money里面的数据时,另一个的money也会跟着修改,这是浅拷贝。
那么如果我们想要两个Person对象里面的money不指向同一块数据,就需要进行深拷贝。
实例如下:
class 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();
/**
* 浅拷贝
* 浅拷贝是将这个类对象拷贝过去,但是其里面的组合类对象不会再拷贝一份,而是指向同一个对象
*/
// @Override
// protected Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
/**
* 深拷贝
* 深拷贝是指将这个对象 及其里面的组合类对象 全部拷贝一份,
* 与浅拷贝不同地方在于,拷贝出来的对象里面的组合对象不会和圆对象指向同一个
*/
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = (Person)super.clone();
tmp.money = (Money)this.money.clone();
return tmp;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
'}';
}
}
public class Test3 {
public static void main(String[] args) throws CloneNotSupportedException{
Person person1 = new Person();
person1.id = 99;
Person person2 = (Person)person1.clone();
person2.money.m = 1999;
System.out.println("person1: " + person1.money.m);
System.out.println("person2: " + person2.money.m);
}
}
我们先将person1的数据进行浅拷贝到一个的Person类对象,然后将person1的money拷贝到新对象中的money(Money类也序要实现clone接口),这时两个对象的money的指向就不同了,但是里面的数据时相同的,这就是深拷贝。