12.30_学习Java的day12(详解)

二、接口的默认方法的冲突问题

1、一个实现类同时实现多个接口,当多个接口中包含签名相同的默认方法,方法体不同
方法的签名:【修饰符】 返回值类型 方法名(【形参列表】)

解决方案:
(1)保留其中一个接口的实现
(2)选择自定义,即自己重写

2、当一个实现类继承了父类又实现了接口,当父类中有和接口中的默认方法签名相同的方法时,方法体不同
解决方案:
(1)默认:编译器是保留的是父类的
(2)也可以选择保留其中一个接口的
(3)也可以完全自己重写

public class DefaultMethod {
    public static void main(String[] args) {
        C c = new C();
        c.method();
    }
}
interface A{
    default void method(){
        System.out.println("a");
    }
}
interface B{
    default void method(){
        System.out.println("b");
    }
}
class Father{
    public void method(){
        System.out.println("father");
    }
}
//一个类可以同时实现多个接口
//可以把父类理解为亲生父亲,把接口理解为干爹
//亲生父亲是更亲密关系,所以默认保留的是父类的
class C extends  Father implem

类与类,接口与接口,类与接口的关系:

(1)类与类:单继承的关系
(2)接口与接口:多继承的关系
(3)类与接口之间:一个类可以同时实现多个接口;
接口不能去继承类;
(4)类可以同时继承父类,又实现接口:继承在前,实现在后

向上转型与向下转型:

(1)向上类型转换:

当把子类类型的对象/变量a赋值给父类/父接口的变量b时,自动完成。
无风险: a变量类型 > b变量类型

(2)向下类型转换:

当把父类/父接口/兄弟类型的变量a赋值给子类/实现类/兄弟类型变量b时,强制完成。
有风险, a变量类型 <或≈ b类型 这里<是继承或实现关系,≈是指无继承或实现的同级关系。
编译时:理论上只要a变量类型 <或≈ b类型就可以编译通过,但是String、Integer等类型校验比较严格。
运行时:只有a变量中实际对象的类型 <或就是 b类型才可以成功,否则报ClassCastException异常

注意:
向上类型转换与向下类型转换都是针对编译时类型,
实际上对象的运行时类型并没有“转换”。

类型转换的本质没有变。原来new的是什么类型,就还是什么类型。

public class ClassCast {
    public static void main(String[] args) {
        SuperMan man = new SuperMan();

        //自动类型转换,向上类型转换
        //类型转换,其实可以理解为,看成是什么类型,不是真的是这个类型
        Object o = man;
        Animal a = man;
        Person p = man;
        Swimming s = man;
        Flyable f= man;

        //成功的向下转型
        //o变量的编译时类型是Object类型,Object是SuperMan的父类,所以称为向下转型
        //因为o变量中实际存储的是SuperMan类型,SuperMan类型是=SuperMan,该转型安全
        SuperMan s1 = (SuperMan) o;
        //p变量的编译时类型是Person类型,Person是SuperMan的父类,所以称为向下转型
        //因为p变量中实际存储的是SuperMan类型,SuperMan类型是=SuperMan,该转型安全
        SuperMan s2 = (SuperMan) p;
        //p变量的编译时类型是Person类型,Swimming和Person没有继承也没有实现关系,可以称为同级关系,也需要强制类型转换,
        //也归为向下转型
        //因为p变量中实际存储的是SuperMan类型,SuperMan类型是=SuperMan,该转型安全
        Swimming s3 = (Swimming) p;

       //o编译时类是Object,Object是Person的父类,属于向下转型
        //是否安全?
        //o变量中实际存储的是SuperMan类型,SuperMan类型< Person类型,所以是安全的
        Person p3 = (Person) o;

        //p变量的编译时类型是Person类型,Swimming和Person是同级关系,看成向下转型
        //是否安全?
        //p变量中实际存储的是SuperMan类型,SuperMan<Swimming,是实现关系,安全
        Swimming s4 = (Swimming) p;

        //编译时,s是Swimming类型,Flyable和Swimming是同级关系,我们把它归到向下转型
        //是否安全?
        //s变量中实际存储的是SuperMan类型,SuperMan<Flyable,是实现关系,安全
        Flyable f3 = (Flyable) s;
        System.out.println("----------------------------------------");

        Person person = new Person();
        //编译时,Person和Swimming同级关系,看成向下转型
        //是否安全?
        //person中实际类型是Person类型,person 不是Swimming类型,也不小于Swimming类型,所以是失败的
        Swimming s5 = (Swimming) person;

//        String str = (String)person;//编译不通过
    }
}
interface  Flyable{
    void fly();
}
interface Swimming{
    void swim();
}
abstract class Animal{

}
class Person extends  Animal{
    public void walk(){}
}

//看SuperMan的UML类关系图快捷键:Ctrl + Alt + U
class SuperMan extends Person implements  Flyable,Swimming{

    @Override
    public void fly() {
        System.out.println("上天");
    }

    @Override
    public void swim() {
        System.out.println("入水");
    }

    @Override
    public void walk() {
        System.out.println("入地");
    }
}

三、常用接口

1、java.lang.Comparable接口:自然比较接口,优先考虑

   抽象方法:int compareTo(Object obj)

2、java.util.Comparator接口:定制比较接口,后补考虑

(1)为什么有了Comparable接口还要Comparator接口?

因为Comparable接口不能解决所有问题?
A:员工类:编号、姓名、薪资、年龄…
有一个数组,里面有5个员工对象,
①财务说:把这个5个员工按照薪资排序
②人事说:把这个5个员工按照年龄排序
③咨询说:把这个5个员工按照姓名排序
三个需求同时存在,那么只在Employee类中实现compareTo方法不够用。
我们需要Comparator接口帮我们定制其他的需求。

B:使用第三方的类,我们只有它的.class文件,或者甚至只有它的对象,
但是它的这个对象的类型没有实现Comparable接口,而我们在程序中需要对它们的对象进行排序。
此时我们无法去修改这个类型,让他实现Comparable接口。
所以此时我们仍然需要Comparator接口帮我们定制排序规则。

(2)Comparator接口有抽象方法:

int compare(Object o1, Object o2)

包装类:Double等里面有compare方法

Double类型: static int compare(double d1, double d2) 可以用于比较两个double值,
如果d1 > d2,返回正整数,
如果d1 < d2,返回负整数,
如果d1 = d2,返回值0,

public class Comparator {
    public static void main(String[] args) {
        Employee[] arr = {
                new Employee(1,"张三",23,10000),
                new Employee(2,"李四",21,15000),
                new Employee(3,"王五",25,13000),
                new Employee(4,"赵六",22,90000),
                new Employee(5,"麻子",27,8000)
        };
/*        Employee[] arr = {
                new Employee(1,"Alice",23,10000),
                new Employee(2,"Rose",21,15000),
                new Employee(3,"Lily",25,13000),
                new Employee(4,"Lucy",22,90000),
                new Employee(5,"Kate",27,8000)
        };*/

        //财务是按照薪资排序
        //创建比较器对象,用比较器对象帮我们比较两个员工对象
        SalaryComparator sc = new SalaryComparator();
        MyArrays2.sort(arr,sc);

        //遍历结果
        MyArrays2.print(arr);

        System.out.println("---------------------------------------");
        //人事想要按照年龄
        //创建年类比较器对象
        AgeComparator ac = new AgeComparator();
        MyArrays2.sort(arr, ac);

        //遍历结果
        MyArrays2.print(arr);

        System.out.println("-------------------------------------");
//        ③咨询说:把这个5个员工按照姓名排序,按照英文字母顺序排序
        //创建按照名字比较的比较器对象
        NameComparator nc = new NameComparator();
        MyArrays2.sort(arr,nc);

        //遍历结果
        MyArrays2.print(arr);

        System.out.println("-------------------------------------");
//        ③咨询说:把这个5个员工按照姓名排序,按照拼音顺序比较
        //创建按照名字比较的比较器对象
        PinYinComparator pc = new PinYinComparator();
        MyArrays2.sort(arr, pc);

        //遍历结果
        MyArrays2.print(arr);
     }
}

根父类:

java.lang.Object类的所有方法都会继承到所有的引用数据类型中,我们需要了解它的11个方法的作用,使用规则。
那天学习了5个(toString,finalize,getClass,hashCode,equals)
今天再学习一个:

protected Object clone()throws CloneNotSupportedException

protected可见性范围:本类(Object内部),本包(java.lang),其他包的子类(Object的子类中)
说明: CloneNotSupportedException - 如果对象的类不支持 Cloneable 接口,则重写 clone 方法的子类也会抛出此异常,
以指示无法复制某个实例。
换句话说,你需要支持Cloneable 接口,即实现Cloneable 接口。

    Cloneable 接口没有抽象方法,因为它的功能由Object类的clone()已经实现了,我们所有类型都有这个方法,所以你不用重写了。

重写的要求:

(1)方法名:必须相同
(2)形参列表:必须相同
(3)返回值类型:
基本数据类型和void:必须相同
引用数据类型:<=
(4)权限修饰符:>=
(5)其他修饰符:不能是static, final, private等

public class Cloneable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student stu = new Student(1,"张三");
        Object cloneObj = stu.clone();//因为继承的Object的clone方法的修饰符是protected,意味着只能从Student类的内部去调用
/*
        除非,我对这个方法进行重写,并且把protected修改为public
         */
//        此时cloneObj和stu两个对象是复制品的关系
        System.out.println(stu);
        System.out.println(cloneObj);

        System.out.println(stu == cloneObj);//比较地址  不同  false
        System.out.println(stu.equals(cloneObj));//返回true还是false,要看是否重写了
    }
}
class Student implements Cloneable

类的结构:

【修饰符】 class 类名 【extends 父类】 【implements 接口们】{
//(1)成员变量
【修饰符】 数据类型 成员变量名;

//(2)构造器
【修饰符】 类名(){
  }
【修饰符】 类名(形参列表){
  }

//(3)成员方法
【修饰符】 返回值类型 方法名(【形参列表】){
}

//(4)代码块
{
//非静态代码块
}
static{
//静态代码块
}

//(5)成员内部类
}

一、内部类

1、什么是内部类?
声明在其他类的里面的类称为内部类。

2、内部类有两大类/四小类?
根据内部类的声明的位置不同分为两大类:
(1)成员内部类
又根据是否有static修饰,再细分为两类:
A:静态内部类
B:非静态成员内部类

(2)局部内部类
又根据是否有名字来分:
A:有名字的局部内部类(非常少见)
B:匿名内部类

和变量的分类有点像:成员变量(静态变量和实例变量)和局部变量

(一)静态内部类

1、语法结构

【修饰符】 class 外部类名 【extends 父类】 【implements 接口们】{
【其他修饰符】 static class 静态内部类名 【extends 父类】 【implements 接口们】{
}
}

2、特点

(1)静态内部类也是一个类
==>①可以有自己的名字、父类、父接口
②可以有自己的类结构:成员变量、构造器、代码块、成员方法、内部类
③有自己的字节码文件
每一个类都有自己的字节码文件,不管是外部类还是内部类
(2)静态内部类也可以创建对象
(3)修饰符:
外部类的修饰符:public,缺省,final,abstract
静态内部类的修饰符:public,protected,缺省,private,final,abstract,static

3、如何使用它

(1)在外部类中使用:正常使用
(2)在外部类的外面的其他类中:
只要在静态内部类的前面冠以外部类名.即可正常使用。

4、如何在静态内部类中使用外部类的成员

只有一种情况不能使用:在静态内部类中,不能直接使用外部类的非静态的成员

public class StaticInner {
    public static void main(String[] args) {
        //调用Inner的inMethod()和inFun()
        Outer.Inner.inMethod();

        Outer.Inner in = new Outer.Inner();
        in.inFun();

        //此时使用import语句,简化了类名
        Inner in2 = new Inner();
        in.inFun();
    }

}

class Outer{
    private int a;
    private static int b;

    static class Inner {
        public static void inMethod(){
            System.out.println("静态内部类的静态方法");
//            System.out.println("a = " + a);//报错,Inner是静态的,而a是非静态的
            System.out.println("b = " + b);
        }

        public void inFun(){
            System.out.println("静态内部类的静态方法");
        }
    }

    public void test(){
        //调用Inner的inMethod()和inFun()
        Inner.inMethod();

        Inner in = new Inner();
        in.inFun();
    }

    public static void outMethod(){
        //调用Inner的inMethod()和inFun()
        Inner.inMethod();

        Inner in = new Inner();
        in.inFun();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值