接口
接口
接口就是公共的行为规范,只要实现时符合标准就可以通用.
接口可以看成是: 多个类的公共规范,是一种引用数据类型.
使用关键字
interface
实现接口.接口是不能被实例化的.
接口中的成员变量默认是
public static final
接口中只能有抽象方法,当中的方法不写,也是
public abstract
的,不能实现这个方法.
- 如果非要实现,从JDK8之后,那么这个方法只能是
default
修饰的方法.接口中的成员变量是必须初始化的,也就说明接口中没有构造函数,不能有构造方法代码块的
接口用类实现,需要使用
implements
调用.然后重写接口 中的方法即可.重写的时候,子类的访问修饰权限一定要>=父类的,重写函数时要注意权限书写.
interface IUsb{ void openDevice();//默认是public abstract void closeDevice(); } abstract class Mouse implements IUsb { //如果不想重写接口中函数,需要将这个类声明为抽象类 }
interface IShape{
public abstract void draw();
public String name="";
public static int age=10;
public static final int size=20;
void func1();
public abstract void func3();
//默认成员函数
default void func2(){//不写default,error
System.out.println("interface IShape func2()");
}
//静态成员函数
public static void staticFunc(){
System.out.println();
}
// IShape(){} error
}
class Rect implements IShape{//接口,必须将其中的所有方法都重写
public void draw(){
System.out.println("矩形: draw()");
}
@Override
public void func1() {
System.out.println("矩形: func1");
}
@Override
public void func3() {
System.out.println("矩形: func3");
IShape.super.func2(); //调用时,需要引上IShape才能使用super
}
@Override
public void func2() {//对默认成员函数也可以完成重写
System.out.println("矩形:func2");
}
}
public class interfaceCode {
public static void func(IShape ishape){//向上转型
ishape.draw();//实现多态
}
public static void main(String[] args) {
IShape ishape1 = new Rect();
func(ishape1);
//矩形: draw()
IShape.staticFunc();//矩形: draw() 通过接口名访问接口中的静态方法
}
public static void main1(String[] args) {//向上转型
IShape ishape1 = new Rect();
ishape1.draw();
ishape1.func1();
ishape1.func2();
ishape1.func3();
//矩形: draw()
//矩形: func1
//矩形:func2
//矩形: func3
}
}
例子: 电脑键盘鼠标
import javafx.scene.input.KeyCode;
interface IUsb{
void openDevice();
void closeDevice();
}
class Mouse implements IUsb{
public Mouse() {
super();
}
@Override
public void openDevice() {
System.out.println("打开鼠标");
}
@Override
public void closeDevice() {
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("点击鼠标");
}
}
class KeyBoard implements IUsb{
@Override
public void openDevice() {
System.out.println("打开键盘");
}
@Override
public void closeDevice() {
System.out.println("关闭键盘");
}
public void click(){
System.out.println("敲击键盘");
}
}
class Computer{
public void useDevice(IUsb iusb){//参数向上转型,动态绑定实现多态.只需要各个子类都完成了接口的重写即可
iusb.openDevice();
if(iusb instanceof Mouse){
Mouse mouse = (Mouse) iusb;//向下转型,判定之后调用即可
mouse.click();
}else if(iusb instanceof KeyBoard){
KeyBoard keyboard = (KeyBoard) iusb;
keyboard.click();
}
iusb.closeDevice();
}
}
public class interfaceCode{
public static void main(String[] args) {
Computer computer = new Computer();
KeyBoard keyBoard= new KeyBoard();
Mouse mouse = new Mouse();
computer.useDevice(mouse);
System.out.println("=================");
computer.useDevice(keyBoard);
//打开鼠标
//点击鼠标
//关闭鼠标
//=================
//打开键盘
//敲击键盘
//关闭键盘
}
}
一个类实现多个接口
java只支持单继承,不支持多继承.所以可以以接口的形式出现.
package demo1;
abstract class Animal{
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
}
interface IRunning {
void run();
}
interface ISwimming{
void swim();
}
interface IFly{
void fly();
}
class Robot implements IRunning{
@Override
public void run() {
System.out.println("机器人正在跑");
}
}
//鸭子水路空三栖生物,那么就重写三个接口即可
class Duck extends Animal implements ISwimming,IFly,IRunning{//接口之间 , 隔开
public Duck(String name, int age) {
super(name, age);
}
@Override
public void run() {
System.out.println(name+ " is running !!");
}
@Override
public void swim() {
System.out.println(name + "is swimming!!");
}
@Override
public void fly() {
System.out.println(name + " is flying!!");
}
}
class Bird extends Animal implements IFly{
public Bird(String name, int age) {
super(name, age);
}
@Override
public void fly() {
System.out.println(name + " is flying!!");
}
}
class Fish extends Animal implements ISwimming{
Fish(String name,int age){
super(name,age);
}
@Override
public void swim() {
System.out.println(name + "is swimming!!");
}
}
class Dog extends Animal implements IRunning{//必须得写成先继承,再实现接口
public int a;
public Dog(String name, int age, int a) {
super(name, age);//和this(name,age,a)冲突注意!!!
this.a = a;
}
@Override
public void run() {//重写接口方法
System.out.println(name+ " is running !!");
}
}
//class Dog extends Animal{
// public int a;
//
// public Dog(String name, int age, int a) {
// super(name, age);//和this(name,age,a)冲突注意!!!
// this.a = a;
// }
// //此时想给狗添加一个run()方法,但是还不能在Animal中添加并重写,因为不是所有的动物都能跑
// //run()属于一部分动物能力,你会想到再写一个类A,继承A,然后重写run()方法,
// //但是java不支持多继承,所以可以将这一部分动物的共性run -> 写成接口的形式重写
//
//}
public class Test {
public static void iwalk(IRunning iRunning){//只要是实现了IRunning接口的都可以接收
iRunning.run();
}
public static void iswim(ISwimming iSwimming){//只要是实现了ISwimming接口的都可以接收
iSwimming.swim();
}
public static void ifly(IFly iFly){//只要是实现了IFly接口的都可以接收
iFly.fly();
}
public static void main(String[] args) {
Dog dog=new Dog("xd1",10,20);
Duck duck =new Duck("xd2",20);
iwalk(dog);
iwalk(duck);
//xd1 is running !!
//xd2 is running !!
iwalk(new Robot());//即使不是动物类型,只要是实现了这个IRunning接口就可以接收
//机器人正在跑
Fish fish =new Fish("xd3",30);
iswim(fish);
iswim(duck);
//xd3is swimming!!
//xd2is swimming!!
Bird bird= new Bird("xd4",40);
ifly(bird);
ifly(duck);
//xd4 is flying!!
//xd2 is flying!!
}
}
接口之间的继承
其实是接口的拓展extends
真实含义是这样的.
package demo1;
interface A{
void funcA();
}
interface B{
void funcB();
}
interface CC extends A,B{
//因为是继承(拓展),对象那里会要求你走父类构造函数.但是因为接口并不需要构造函数,所以不用写
void funcC();
}
class Y implements CC{//需要将三个接口中的函数都重写
@Override
public void funcA() {
System.out.println("Y funcA");
}
@Override
public void funcB() {
System.out.println("Y funcB");
}
@Override
public void funcC() {
System.out.println("Y funcC");
}
}
public class test2 {
}
接口使用实例
package demo1;
import java.util.Arrays;
//class Student
class Student implements Comparable<Student>{//重写接口,指定比较规则
public String name;
@Override
public int compareTo(Student o) {//student[0].compareTo(student[1])//参数列表前面有一个隐含的this引用
// return this.score-o.score; //指定根据分数进行比较
// if(this.score<o.score){
// return -1;
// }
// else if(this.score>o.score){
// return 1;
// }
// else {
// return 0;
// }
//指定根据String名字进行比较
if(this.name .compareTo(o.name)<0){//Sting 也是一个类,也得调用compareto方法.String类中肯定也重写了Comparable<String>接口
return -1;
}
else if(this.name.compareTo(o.name)>0){
return 1;
}
else{
return 0;
}
}
public int age;
public int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
public class test3 {
//向上转型
public static void sort(Comparable[] array){//因为Student重写了接口,所以这个函数可以接收所有重写这个接口的对象
//可以使用冒泡排序实现排序
for (int i =0; i < array.length-1; i++) {//趟数,一趟搞定一个数
for(int j=0;j< array.length-1-i;j++){//下一趟就整-i个数就行了,提升效率
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[] student =new Student[3];
student[0]=new Student("zhangsan",20,30);
student[1]=new Student("lisi",30,50);
student[2]=new Student("wangwu",40,10);
//1. 自己实现一个比较函数
sort(student);
System.out.println(Arrays.toString(student));
//2. Array自带的sort,然后重写比较接口即可
Arrays.sort(student);
//terminal
// public interface Comparable<T> {
// public int compareTo(T o);
//}
System.out.println(Arrays.toString(student));
}
}
- 但是Student中比较规则写死了,能不能灵活一点呢?
package demo2;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
//class Student implements Comparable<Student>{
// public String name;
// public int age;
// public int score;
//
// @Override
// public int compareTo(Student o) {
if(this.score > o.score) {
return 1;
}else if(this.score<o.score){
return -1;
}else{
return 0;
}
// return this.score-o.score;
// }
//
// public Student(String name, int age, int score) {
// this.name = name;
// this.age = age;
// this.score = score;
// }
//
// @Override
// public String toString() {
// return "Student{" +
// "name='" + name + '\'' +
// ", age=" + age +
// ", score=" + score +
// '}';
// }
//}
class Student{
public String name;
public int age;
public int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
class ScoreComp implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.score-o2.score;
}
}
//比较器类,很灵活.首先传参方面,相对于上面,参数顺序可以自定义,因为上面默认前面的是this引用.
//比较方式可以自定义,不会写死.
class NameComp implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
class AgeComp implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;
}
}
public class test1 {
public static void sort(Comparable[] arrays){
for(int i=0;i<arrays.length-1;i++){
for(int j=0;j<arrays.length-1-i;j++){
if(arrays[j].compareTo(arrays[j+1]) >0){
Comparable tmp= arrays[j];
arrays[j]=arrays[j+1];
arrays[j+1]=tmp;
}
}
}
}
public static void main(String[] args) {
Student[] students =new Student[3];
students[0]= new Student("zhangsan",20,30);
students[1]= new Student("lisi",10,40);
students[2]= new Student("wangwu",40,10);
ScoreComp scoreComp =new ScoreComp();
Arrays.sort(students,scoreComp);
System.out.println(Arrays.toString(students));
NameComp nameComp =new NameComp();
Arrays.sort(students,nameComp);
System.out.println(Arrays.toString(students));
AgeComp ageComp=new AgeComp();
Arrays.sort(students,ageComp);
System.out.println(Arrays.toString(students));
}
// public static void main1(String[] args) {
// Student[] students =new Student[3];
// students[0]= new Student("zhangsan",20,30);
// students[1]= new Student("lisi",10,40);
// students[2]= new Student("wangwu",40,10);
//
// sort(students);
// System.out.println(Arrays.toString(students));
//
// Arrays.sort(students);
// System.out.println(Arrays.toString(students));
// }
}
Cloneable
如果想要克隆一个对象,
- C++中提供拷贝构造和赋值构造函数,默认是浅拷贝,自定义实现是深拷贝.
- 那么java中,就需要在这个类重写Cloneable接口.
- 对自定义类型进行拷贝
package demo3;
class Student implements Cloneable{
public String name;
public int age;
public int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
//返回值是Object,是所有类的父类
@Override
protected Object clone() throws CloneNotSupportedException {//1
return super.clone();
}
}
public class test {
public static void main(String[] args) throws CloneNotSupportedException{//添加异常处理,针对 1
Student student1 =new Student("yuanwei",22,20);
Student student2 = (Student)student1.clone();//Object -> Student ,向下转型,需要强转
System.out.println(student1);
System.out.println(student2);
}
}
浅拷贝
package demo3;
class Money{
public int pay = 100;
}
class Student implements Cloneable{
public String name;
public int age;
public int score;
public Money m=new Money();//组合的形式添加另一个类,成员变量m存放的是这个的引用
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
//返回值是Object,是所有类的父类
@Override
protected Object clone() throws CloneNotSupportedException {//1
return super.clone();
}
}
public class test {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1 =new Student("yuanwei",22,20);
Student student2 = (Student)student1.clone();//Object -> Student ,向下转型,需要强转
System.out.println(student1.m.pay);
System.out.println(student2.m.pay);
System.out.println("+++++++++++++++++");
student1.m.pay =20;
System.out.println(student1.m.pay);
System.out.println(student2.m.pay);
//100
//100
//+++++++++++++++++
//20
//20
//更改其中一个,两个都会修改.说明Object提供的只是浅拷贝
}
}
深拷贝
package demo3;
class Money implements Cloneable{
public int pay = 100;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student implements Cloneable{
public String name;
public int age;
public int score;
public Money m=new Money();//组合的形式添加另一个类,成员变量m存放的是这个的引用
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
//返回值是Object,是所有类的父类
@Override
protected Object clone() throws CloneNotSupportedException {
//在堆上克隆了一个新的student对象,
Student newStudent = (Student) super.clone();//调用Object的clone(),然后u向下转型为Student
//在堆上另外克隆一个Money对象
newStudent.m=(Money)this.m.clone();//this 是Student1,谁调用this就是谁
return newStudent;//返回值是栈中newStudent,也就是新的对象的引用
// return super.clone();
}
}
public class test {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1 =new Student("yuanwei",22,20);
Student student2 = (Student)student1.clone();//Object -> Student ,向下转型,需要强转
System.out.println(student1.m.pay);
System.out.println(student2.m.pay);
System.out.println("+++++++++++++++++");
student1.m.pay =20;
System.out.println(student1.m.pay);
System.out.println(student2.m.pay);
//自定义Student中Object的clone方法之后,提供的是深拷贝
//100
//100
//+++++++++++++++++
//20
//100
}
}
抽象类和接口的区别
语法层面上的区别
- 1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
- 2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
- 3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
- 4)一个类只能继承一个抽象类,而一个类却可以实现多个接口.
相同点
(1)都不能被实例化 (2)接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。
不同点
(1)接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。
(2)实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
(3)接口强调特定功能的实现,而抽象类强调所属关系。
(4)接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。
equals
package demo3;
import java.util.Objects;
class StudentH {
public String name;
public int age;
public int score;
// public Money2 m=new Money2();//组合的形式添加另一个类,成员变量m存放的是这个的引用
public StudentH(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
//重写父类中的equals方法,自己实现的
// public boolean equals(Object obj) {
// if(obj==null)
// return false;
// if(this == obj){
// System.out.println("指向同一个对象");
// return true;
// }
// if(!(obj instanceof Student)){//如果传来的不是Student类型
// System.out.println("比较的两个对象都不是一个类型");
// return false;
// }
// StudentH newStudnet =(StudentH) obj;
//
// if(this.name.equals(newStudnet.name)){//调用String类型重写Object的equals方法
// return true;
// }
// else {
// return false;
// }
// }
//可以使用编译器Generate的equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StudentH studentH = (StudentH) o;
return age == studentH.age && score == studentH.score && Objects.equals(name, studentH.name);
}
//Objects是Object的一个工具类
@Override
public int hashCode() {//native方法,底层是由伟大的C++代码写的!!!
return Objects.hash(name, age, score);
//算一个具体对象位置,是一个内存地址,然后调用方法将这个地址以16进制输出
}
}
public class test_equals {
public static void main(String[] args) {
StudentH student1 = new StudentH("yuanwei", 22, 20);
StudentH student2 = new StudentH("yuanwei", 22, 20);
System.out.println(student1.name);
System.out.println(student2.name);
//我们希望同名的人,放到同一个位置.
System.out.println(student1.hashCode());
System.out.println(student1.hashCode());
//1542478095
//1542478095
}
public static void main2(String[] args) {
StudentH student1 = new StudentH("yuanwei", 22, 20);
StudentH student2 = new StudentH("yuanwei", 22, 20);
System.out.println(student1.name);
System.out.println(student2.name);
//yuanwei
//yuanwei
//我们的逻辑是,只要是名字相同的两个学生,就认为是一个人,实现equals方法
boolean flag= student1.equals(student2);//调用重写之后的equals
System.out.println(flag);//true
}
public static void main1(String[] args) throws CloneNotSupportedException {
StudentH student1 = new StudentH("yuanwei", 22, 20);
StudentH student2 = new StudentH("yuanwei", 22, 20);
System.out.println(student1.name);
System.out.println(student2.name);
//yuanwei
//yuanwei
//我们的逻辑是,只要是名字相同的两个学生,就认为是一个人,实现equals方法
System.out.println(student1==student2);//false 比较的是对象引用是否相同,很明显不同对象引用不同
boolean flag= student1.equals(student2);//默认调用的就是Object的equals方法
// public boolean equals(Object obj) {
// return (this == obj);//比较的很明显是对象引用是否相等,
// }
System.out.println(flag);//false
}
}