目录
1.抽象类
2.接口
2.1实现多个接口
2.2接口之间的关系
2.3接口使用实例
2.3.1Comparable接口
2.3.2Comparator接口
2.3.2Clone接口
2.4抽象类与接口的区别
3.Object类
3.1getClass方法
3.2equals方法
3.3hashcode方法
1.抽象类
定义:抽象方法:这个方法没有具体的实现;
抽象类:不能完全代表一个具体的对象。
注意:
1> 使用 abstract 修饰;
2> 抽象类不能进行实例化,但普通类可以;
3> 抽象类中不一定包含抽象方法,但包含抽象方法的类一定是抽象类;
4> 抽象类中可以定义普通的成员变量和成员方法;
5> 抽象类存在的最大意义就是为了被继承,且多了一层编译器的校验;
6> 普通类继承抽象类后要重写抽象类中的抽象方法;
7> 抽象类A继承抽象类B后不需要重写,但当普通类C再继承抽象类A后,要重写所有没被重写的抽象方法;
8> 要满足重写的要求(如static和private不能被重写);
9> final关键字不可能和abstract同时作用在一个类或方法上;
10> 抽象类当中可以存在构造方法,在子类实例化时,会帮助父类的成员进行初始化。
abstract class Shape { //抽象类
public int a;//普通成员变量
public void print() { //普通成员方法
System.out.println("Shape");
}
public abstract void draw(); //抽象方法
}
class Cycle extends Shape { //普通类
@Override //普通类继承抽象类后要重写抽象类中的抽象方法
public void draw() {
System.out.println("○");
}
}
abstract class Flower extends Shape {
//抽象类继承抽象类,可以不重写父类的抽象方法
abstract public void printf();//抽象方法
}
class Square extends Flower {
@Override //见注意事项6
public void draw() {
System.out.println("□");
}
@Override
public void printf() {
System.out.println("❀");
}
}
2.接口
定义:对公共行为的规范标准,是一种引用数据类型。相当于抽象类的进一步抽象。
注意:
1> 使用 interface 定义;
2> 接口中不能有实现的方法,但是静态方法和被default修饰的方法可以实现;
3> 接口中的成员方法默认是public abstract修饰的;
4> 接口中的成员变量默认是public static final 修饰的;
5> 不能通过关键字new来实例化;
6> 类和接口之间使用implement进行关联;
7> 类实现接口后要重写接口中的抽象方法;
8> 接口中存在default方法时可重写可不重写,具体看业务需求;
9> 不论是接口还是抽象类,都有向上转型;
10> 子类实现接口方法时,这个方法一定要public修饰;
11> 接口中没有构造方法和代码块;
12> 当一个类不想实现接口当中的方法时,这个类可以被定义为抽象类;
13> 接口的修饰符可以为abstract、public,不能为protected、private、final。
interface IShape { //接口
//成员方法默认为public abstract修饰,顾下列方法均为抽象方法
public abstract void draw1();//抽象方法不可实现,public abstract可省略
public void draw2();//抽象方法不可实现,public可省略
public static void draw3() { //静态方法可以实现
System.out.println("draw3");
}
default public void draw4() { //被default修饰的方法可以实现
System.out.println("draw4");
}
}
class Cycle implements IShape { //Cycle类实现了IShape接口
@Override //重写接口中的抽象方法
public void draw1() {
System.out.println("○");
}
@Override //重写接口中的抽象方法
public void draw2() {
System.out.println("□");
}
}
class Rect implements IShape { //同上
@Override
public void draw1() {
System.out.println("□");
}
@Override
public void draw2() {
System.out.println("○");
}
}
public class Test {
public static void drawMap(IShape shape) { //多态
shape.draw1();
}
public static void main(String[] args) {
//IShape iShape = new IShape();//接口无法实例化自己
IShape iShape1 = new Cycle();
IShape iShape2 = new Rect();//向上转型
drawMap(new Cycle());
drawMap(new Rect());
}
}
2.1实现多个接口
意义:一个类实现多个接口,可以解决Java中多继承的问题。
注意:先继承类,再实现接口。
interface IFlying { //接口1
void fly();
}
interface ISwimming { //接口2
void swim();
}
interface IRunning { //接口3
void run();
}
abstract class Animal { //抽象父类
public String name;
public int age;
public Animal(String name, int age) { //带两个参数的构造方法
this.name = name;
this.age = age;
}
public abstract void eat(); //抽象方法
}
class Dog extends Animal implements IRunning,ISwimming{ //子类1
public Dog(String name, int age) { //子类的构造方法
super(name, age);
}
@Override //重写父类和接口的抽象方法
public void swim() {
System.out.println(this.name+"正在狗刨");
}
@Override
public void run() {
System.out.println(this.name+"正在跑");
}
@Override
public void eat() {
System.out.println(this.name+"正在吃狗粮");
}
}
class Bird extends Animal implements IFlying { //子类2
public Bird(String name, int age) { //子类的构造方法
super(name, age);
}
@Override //重写父类和接口的抽象方法
public void fly() {
System.out.println(this.name+"正在飞");
}
@Override
public void eat() {
System.out.println(this.name+"正在吃虫子");
}
}
public class Test {
public static void testEat(Animal animal) { //多态
animal.eat();
}
public static void testFly(IFlying iFlying) { //多态
iFlying.fly();
}
public static void testRun(IRunning running) { //多态
running.run();
}
public static void testSwim(ISwimming iSwimming) { //多态
iSwimming.swim();
}
public static void main(String[] args) {
testEat(new Bird("小鸟",3));
testEat(new Dog("小狗",3));
testFly(new Bird("小小鸟",2));
testRun(new Dog("小小狗",2));
testSwim(new Dog("小小小狗",1));
}
}
2.2接口之间的关系
接口与接口之间关联用 extends,意为拓展,非继承。相当于把接口合并在一起。
interface A {
void testA();
}
interface B {
void testB();
}
interface C extends A,B { //此时C接口不仅有自己的功能,还有A接口和B接口的功能
void testC();
}
class D implements C { //ABC中的抽象方法都要重写
@Override
public void testA() {
}
@Override
public void testB() {
}
@Override
public void testC() {
}
}
2.3接口使用实例
2.3.1Comparable接口
//只根据年龄或成绩比较:
import java.util.Arrays;
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 //重写Comparable接口中的抽象方法
public int compareTo(Student o) { //按年龄排序
/*if (this.age - o.age > 0) {
return 1;
} else if (this.age - o.age == 0) {
return 0;
}else {
return -1;
}*/
return this.age - o.age;
}
}
public class Test {
//模拟实现冒泡排序
public static void bubbleSort(Comparable[] comparables) { //传入Comparable类型(实现了可比较接口)的数组
for (int i = 0; i < comparables.length-1; i++) {
for (int j = 0; j < comparables.length-1-i; j++) {
//if (comparables[j]>comparables[j+1]) //无法直接比较
if(comparables[j].compareTo(comparables[j+1]) > 0) { //使用重写的compareTo方法比较
Comparable tmp = comparables[j];
comparables[j] = comparables[j+1];
comparables[j+1] = tmp;
}
}
}
}
public static void main(String[] args) {
Student[] array = new Student[2];
array[0] = new Student("zhangsan",20,88.8);
array[1] = new Student("lisi",18,90);
bubbleSort(array); //冒泡排序
System.out.println("排序后:"+Arrays.toString(array));
}
public static void main2(String[] args) {
Student student1 = new Student("xiaoming",14,98.5);
Student student2 = new Student("xiaohong",16,59.9);
int ret = student1.compareTo(student2);
System.out.println(ret); //-1
}
public static void main1(String[] args) {
Student[] array = new Student[3];
array[0] = new Student("zhangsan",20,88.8);
array[1] = new Student("lisi",18,90);
array[2] = new Student("wangwu",21,68.9);
System.out.println("排序前:"+ Arrays.toString(array));
Arrays.sort(array); //Java自带的方法
System.out.println("排序后:"+ Arrays.toString(array));
}
}
2.3.2Comparator接口
//年龄成绩均可比较: 更加灵活
import java.util.Comparator;
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;
}
}
class AgeComparator implements Comparator<Student> { //比较年龄
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
class ScoreComparator implements Comparator<Student> { //比较成绩
@Override
public int compare(Student o1, Student o2) {
return (int)(o1.score - o2.score);//score为double类型,需要强转为int类型
}
}
public class Test {
public static void main(String[] args) {
Student student1 = new Student("xiaoming",14,98.5);
Student student2 = new Student("xiaohong",16,59.9);
AgeComparator ageComparator = new AgeComparator();
int ret = ageComparator.compare(student1,student2);
System.out.println(ret);//-2
ScoreComparator scoreComparator = new ScoreComparator();
int ret2 = scoreComparator.compare(student1,student2);
System.out.println(ret2);//38
}
}
2.3.2Clone接口
class Student implements Cloneable { //实现Cloneable接口
public int age;
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException { //异常
return super.clone();//子类重写的Object只是调用了父类的clone方法
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student(18);
Student student2 = (Student) student1.clone();//向下转型,clone类型为Object,需强转为Student
System.out.println(student1);//Student{age=18}
System.out.println(student2);//Student{age=18} 克隆成功
}
}
Ctrl+点击进入Cloneable接口后发现,该接口内什么东西都没有,why??
答:这个接口被叫做标记接口,实现该接口证明当前的类是可以被克隆的。
//浅拷贝
class Money {
public double money;
}
class Student implements Cloneable { 实现Cloneable接口
public int age;
public Money m = new Money();
public Student(int age) {
this.age = age;
}
@Override //重写接口中的抽象方法
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student(18);
student1.m.money = 9.15;
Student student2 = (Student) student1.clone();//克隆student1
System.out.println(student1.m.money);//9.15
System.out.println(student2.m.money);//9.15
student1.m.money = 10;//更改student1
System.out.println(student1.m.money);//10 按理说只有student1变
System.out.println(student2.m.money);//10 但是实际上两个都变了
//这就是浅拷贝,没有克隆当前对象内更深层的变量
}
}
//深拷贝
class Money implements Cloneable { //实现Cloneable接口
public double money;
@Override //重写接口中的抽象方法
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student implements Cloneable { //实现Cloneable接口
public int age;
public Money m = new Money();
public Student(int age) {
this.age = age;
}
@Override //重写接口中的抽象方法
protected Object clone() throws CloneNotSupportedException {
Student tmp = (Student) super.clone();//先克隆当前对象
tmp.m = (Money) this.m.clone();//再克隆当前对象里更深层的变量
return tmp;
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student(18);
student1.m.money = 9.15;
Student student2 = (Student) student1.clone();//克隆student1
System.out.println(student1.m.money);//9.15
System.out.println(student2.m.money);//9.15
student1.m.money = 10;//更改student1
System.out.println(student1.m.money);//10 深拷贝,只修改了student1
System.out.println(student2.m.money);//9.15 不影响student2内的值
}
}
2.4抽象类与接口的区别
区别 | 抽象类(abstract) | 接口(interface) |
---|---|---|
结构组成 | 普通成员变量+抽象方法 | 抽象方法+全局变量 |
权限 | 各种权限 | public |
子类使用 | 使用extends继承抽象类 | 使用implement实现接口 |
关系 | 一个抽象类可以实现若干接口 | 借口不能继承抽象类,但可使用extends拓展多个父接口 |
子类限制 | 一个子类只能继承一个抽象类 | 一个子类可以实现多个接口 |
3.Object类
定义:Object是Java默认提供的一个类,是参数的最高同一类型。除了Object类,所有的类都是存在继承关系的。默认所有类继承Object父类。
疑问:之前我们学过,一个类只能继承一个类,这里的意思是只能同时继承一个类。
例如:Dog类继承Animal类,而Animal类又默认继承Object类,所以Dog类间接继承了Object类,没有违背一个类只能继承一个类这一说明。
//使用Object类接收所有类的对象
class Student {
public int age;
public Student(int age) {
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Object object1 = new Student(1);//Object可接收所有类的对象
}
}
3.1getClass方法
public class Test {
public static void main(String[] args) {
Student student = new Student(10);
Class<?> c = student.getClass();//Class<?> 这里涉及到了泛型,在之后的数据结构中会讲解
System.out.println(c);//class Demo2.Student —— 在Demo2包下的Student类中
}
}
3.2equals方法
进入Object的equals方法后,我们发现代码仍是使用地址比较,所以若想比较数据大小,必须要重写equals方法:
import java.util.Objects;
class Student {
public int age;
public Student(int age) {
this.age = age;
}
@Override //根据自身需求重写equals方法
public boolean equals(Object obj) {
Student student = (Student) obj;
return age == student.age;
}
}
public class Test {
public static void main(String[] args) {
Student student1 = new Student(10);
Student student2 = new Student(10);
System.out.println(student1==student2);//比较地址,false
//System.out.println(student1.equals(student2));//父类Object中的equals仍是比较地址,false
System.out.println(student1.equals(student2));//重写equals后比较年龄大小,true
}
}
3.3hashcode方法
定义:此方法帮我们算了一个具体的对象位置,用来确定对象在内存中存储的位置是否相同。一般在散列表中才有用,其他情况下无用。
import java.util.Objects;
class Student {
public int age;
public Student(int age) {
this.age = age;
}
@Override //使用Generate生成
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;
}
@Override //使用Generate生成
public int hashCode() {
return Objects.hash(age);
}
}
public class Test {
public static void main(String[] args) {
Student student1 = new Student(10);
Student student2 = new Student(10);//没重写hashCode:不一样
//System.out.println(student1.hashCode());//460141958
//System.out.println(student2.hashCode());//1163157884
//重写hashCode后:一样
System.out.println(student1.hashCode());//41
System.out.println(student2.hashCode());//41
}
}
第一篇万字博客,爽 dei dei ~~~