一、接口基本概述
public interface TestInterface {
//成员变量默认static
public String name="1";
public static int age=0;
//抽象方法()相当于公共标准的意思
public abstract void draw();//不能有具体实现,默认Publid abstract
//从java8开始提供default来支持方法具体实现
default public void func(){
System.out.println("hello");
}
public static void fun1(){
System.out.println("类名直接调用方法");
}
}
class Rect implements TestInterface{
public void draw(){
System.out.println("矩形");
}
}
class Flower implements TestInterface{
public void draw(){
System.out.println("花");
}
}
接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。
二、举例子
创建一个USB接口
public interface USB {
void openDevice();
void closeDevie();
}
创建鼠标类实现USB接口
public class Mouse implements USB{
@Override
public void openDevice() {
System.out.println("打开鼠标服务");
}
@Override
public void closeDevie() {
System.out.println("关闭鼠标服务");
}
public void click(){
System.out.println("点击鼠标");
}
}
创建键盘类实现USB接口
public class KeyBoard implements USB{
@Override
public void openDevice() {
System.out.println("敲击键盘");
}
@Override
public void closeDevie() {
System.out.println("关闭键盘服务");
}
public void inPut(){
System.out.println("输入服务");
}
}
创建电脑类,无实现USB接口
public class Computer {
public void open(){
System.out.println("开机");
}
public void close(){
System.out.println("关机");
}
public void useDevice(USB usb){//只要实现了USB接口的都能传进来
usb.openDevice();
if (usb instanceof Mouse){
Mouse mouse=(Mouse) usb;//发生向下转型
mouse.click();
}else if (usb instanceof KeyBoard){
KeyBoard keyBoard=(KeyBoard) usb;
keyBoard.inPut();
}
}
}
public class Test {
public static void main(String[] args) {
Computer computer=new Computer();
Mouse mouse=new Mouse();
KeyBoard keyBoard=new KeyBoard();
computer.useDevice(mouse);
computer.useDevice(keyBoard);
}
}
三、第二个例子
创建一个Animal类
public class Animal {
public String name;
public Animal(String name){
this.name=name;
}
}
将动物可能出现的动作规范为接口
public interface IRunning {
public void run();
}
interface ISwimming{
public void swim();
}
创建一个鱼类和狗类,继承父类Animal,实现各自的动作
public class Fish extends Animal implements ISwimming{
public Fish(String name){
super(name);
}
public void swim(){
System.out.println("鱼在游泳");
}
}
public class Dog extends Animal implements IRunning{//先继承再实现
public Dog(String name){
super(name);
}
public void run(){
System.out.println("狗在跑");
}
}
创建一个鸭子类,由于鸭子会游泳和跑步,实现了多个接口,解决类不能多继承的问题
class Duck extends Animal implements IRunning,ISwimming{
public Duck(String name){
super(name);
}
public void run(){
System.out.println("鸭子在跑");
}
public void swim(){
System.out.println("鸭子在游泳");
}
}
public class Test {
//只要实现IRunning接口的都能是实现
public static void walk(IRunning running){
running.run();
}
public static void swim(ISwimming swimming){
swimming.swim();
}
public static void main(String[] args) {
walk(new Dog("旺财"));//发生向上转型
walk(new Duck("唐老鸭"));
}
}
四、接口间的继承
//鳄鱼即会跑也会游泳
//crocodile接口既有自己的方法也有ISwimmingh和IRunning接口的方法
interface crocodile extends ISwimming,IRunning{
//自己的方法
public void hunt();//捕猎
//接口IRunning和接口ISwimming的方法
public void run();
public void swim();
}
五、 对象之间的比较
public class Test {
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("laowu",45,45.23F);
students[1]=new Student("zhangsan",25, 78.23F);
students[2]=new Student("lisi",43,123.34F);
System.out.println(students[0].compareTo(students[1]));
}
}
假如我想对几个对象进行按照某种规则排序排序,可以将被比较的类实现comparable接口,而实现该接口需要重写compareTo方法
class Student implements Comparable<Student>{//实现Comparable接口需要重写compareto方法
public int age;
public String name;
public float score;
public Student (String name,int age,float score){
this.age=age;
this.name=name;
this.score=score;
}
@Override
public String toString() {
return "student{" +
"age=" + age +
", name='" + name + '\'' +
", score=" + score +
'}';
}
//假如以年龄大小比较
public int compareTo(Student o) {
if (this.age>o.age){
return 1;
} else if (this.age < o.age) {
return -1;
}else {
return 0;
}
}
}
假如按name比较,由于String类是实现了comparable接口,那么可以按照以下代码进行比较
public int compareTo(Student o) {
//假如按字符串比较
if (this.name.compareTo(o.name)>0){
return 1;
} else if (this.name.compareTo(o.name)<0) {
return -1;
}else {
return 0;
}
}
下面为String类compareTo源码
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
在test类中写入自己写的Sort方法代码
//实现了Comparable接口的数组都能传进来
public static void sort(Comparable[] array){
for (int i=0;i< array.length;i++){
for (int j=0;j< array.length-1-i;j++){
if (array[j].compareTo(array[j+1])>0){
Comparable tmp=array[j];
array[j]=array[j+1];
array[j+1]=tmp;
}
}
}
}
Sort以冒泡排序的形式,按字符比较,此时在main函数中调用Arrays.toStirng方法
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("laowu",45,45.23F);
students[1]=new Student("zhangsan",25, 78.23F);
students[2]=new Student("lsi",43,123.34F);
System.out.println(students[0].compareTo(students[1]));
sort(students);
System.out.println(Arrays.toString(students));
}
输出结果为按字符大小比较的结果
需要注意的是,一旦在实现了Comparable接口的类中重写了compareTo方法,该方法就固定了,以后调用该方法就只能按字符大小比较,对类的侵入性很强,不够灵活。
基于以上理由,我们可以引入Comparator接口
定义一个类实现Comparator接口,需要重写compare方法,该类以对象的年龄进行比较
class AgeComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;
}
}
在test类中实例化AgeComparator,把ageComparator引用放入Arrays.sort的第二个参数
public class Test {
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("laowu",45,45.23F);
students[1]=new Student("zhangsan",25, 78.23F);
students[2]=new Student("lsi",43,123.34F);
//比较器
AgeComparator ageComparator=new AgeComparator();
Arrays.sort(students,ageComparator);
System.out.println(Arrays.toString(students));
}
}
输出结果为按照年龄大小排序的结果
同样的,定义按照分数大小排序的比较器
class ScoreComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return (int) (o1.score-o2.score);
}
}
调用Arrays.sort时把scoreComparator传进第二个参数
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("laowu",45,45.23F);
students[1]=new Student("zhangsan",25, 78.23F);
students[2]=new Student("lsi",43,123.34F);
AgeComparator ageComparator=new AgeComparator();
ScoreComparator scoreComparator=new ScoreComparator();
Arrays.sort(students,scoreComparator);
System.out.println(Arrays.toString(students));
}
同理,按照字符比较的比较器代码如下
//按照字符比较
class NameComparator implements Comparator<Student>{
public int compare(Student o1,Student o2){
return o1.name.compareTo(o2.name);//String类实现了Comparable接口并重写了compareTo方法,直接调用即可
}
}
六、克隆接口和深拷贝
创建一个类实现Cloneable接口,按住ctrl点击Cloneable,发现该接口无任何抽象方法
class Student implements Cloneable{
public String name;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
但是在测试类里依然不能调用克隆方法
要能调用克隆方法,必须在Student类中重写object类的clone方法,因为object类是所有类的父类
@Override
//调用改方法可能会出现该异常(编译时的异常)
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException{
Student student1=new Student();
student1.name="小猫";
Student student2=(Student) student1.clone();//发生向下整型
System.out.println(student1.name);
System.out.println(student2.name);
}
打印结果如下,此时不是深拷贝
观察以下代码
class Money{
public double money=12.25;
}
class Student implements Cloneable{
public String name;
public Money m=new Money();
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1=new Student();
Student student2=(Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
System.out.println("_______________");
student2.m.money=89;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
}
输出结果如下,可以看到下划线之前money的值为12.25,但是只修改了student2.m.money,发现student1的money也改变了
student2由student1拷贝而来,当修改student2里面的值从而引起原来的对象值也改变,这种叫浅拷浅拷贝原理
图中两行代码的执行流程如上图所示,虽然tsudent2由student1克隆而来,但是student里面的m对象依然指向的是studengt1 里m指向的地址,只拷贝了第一层,没有拷贝更深层的m对象,所以当修改student2.m.money,两个Student对象的m.money值都会改变。要想让student1.m.money的值不改变就必须连m对象也拷贝一份。
深拷贝是指,拷贝而来的对象,当修改该对象的某个值时,不会导致原来的拷贝对像值发生修改
protected Object clone() throws CloneNotSupportedException {
Student student =(Student) super.clone();//这行代码只是克隆了一个Student类的对象,用student接收
student.m=(Money) this.m.clone();//将这个studet的m的对象也克隆一份,并强制转换成Money类型
return student;
}
这时候改变student2.m.money的值,student1的money的值不会受到影响