java基础第一次测试总结,以及==与equals的详细介绍,接口和抽象类的定义和区别

总结:

第一题:
    a++;表示a用完以后再加一
    ++a;表示先给a+1在用a;
    &&:短路与,当前面的条件有不满足则&&后面的代码不执行

第五题:
    子类继承父类当new子类对象是会自动调用父类的构造方法,但是因为创建的是子类对象所以在没有创建父类
    对象时,父类对象为null;因此创建子类对象不一定产生了父类对象

第六题:
    integer类型是int类型的包装类,当范围在-128---127之间时不会new对象来存放值
    当范围在这之外后会开辟内存空间来存放,会导致地址值不同.
    所以,当在-128---129之间时,==比较的是具体值.
         在这范围之外时==比较的是地址值

第七题:
    拥有静态成员的内部类不一定是静态内部类
    因为,内部类中可以有常量,常量的修饰符可以是public static fianl int A = 0;


第八题:
    抽象方法不可以被static关键字修饰;
    因为会编译报错,错误信息:非法的修饰符组合: abstract和static
    final修饰的方法也不可以声明为抽象的;
    因为会编译报错,错误信息::非法的修饰符组合: abstract和final
                
    
    总结:只要是不能重写的方法,都不能声明抽象方法,因为这些方法将来没有办法重写实现。
            注意,抽象方法,就是为了将来让子类中去重写实现的。抽象方法可以调用,但不能执行,调用之后将来执行的一定是这个抽象方法实现。
                (这个抽象方法的实现,在这个抽象类的子类中)
                (需要用到多态和重写)

第十一题:
    public static void main(String[] args){
        int[] arr = {3,4,6,8};
        int len = arr.length*2;
        int[] a = new int[len];
        for(int i=0;i<arr.length;i++){
             a[i] = arr[i];
        }
        arr=a;
    }
    注意:数组扩容要讲扩容后的数组赋给原数组

第十二题:
    public static void main(String[] args){
        List list = new ArrayList();
        test1(list);
        System.out.println(list.size());
        test2(list);
        System.out.println(list.size());
    }
    public static void test1(List list){
        list = null;
    }
    public static void test2(List list){
        list.add("aaaa");
    }

当List list = new ArrayList时不会产生空指针异常
只有当 List list = null;才会产生空指针异常


第十三题:
    启动类加载器,扩展类加载器,系统类加载器,自定义类加载器
    作用:
        类加载器会通过classpath中的配置路径,来查找当前需要执行的java代码所存在的class文件

第十四题:
      Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2永远被阻塞了。导致了死锁。
    

第十五题:
    当调用intern方法时,如果池已经包含与该字符串相同的String对象的字符串,则返回来自池的字符串。 否则,此String对象将添加到池中,并返回对此String对象的引用。 

第十六题:
    == 是操作符不能被重写,可以比较引用类型和基本数据类型
    比较引用类型时比较的是地址值,比较基本数据类型时比较的是具体值

    equals 是方法可以被重写,如果被重写后则按照重写的方法来比较,如果没有被重写
    比较的是具体值

第十七题:
    八大基本数据类型:
        整数型    
            byte        8 位        1字节
            short        16位        2字节
            int            32位        4字节
            long        64位        8字节
        
        浮点型
            float        32位        4字节
            double        64位        8字节
        字符型
            char        16位      2字节
    
        布尔型
            boolean        8位        1字节

String是引用类型


第十八题:
获取类类型的三种方式:
    1.Class.forName("全限类名<包名.类名>");
    2.类名.Class
    3.对象名.getClass();

    基本数据类型也可以获取Class对象
​            例如:
​                //使用Class对象来表示基本类型
​                public void test1(){
​                    //这个对象c就代表java中的int类型
​                    Class c = int.class;
​                    //判断对象c所代表的类型是否是基本类型
​                    System.out.println(c.isPrimitive());
​                    //获取对象c所代表的类型的名字
​                    System.out.println(c.getName());
​                }


第二十四题:
    创建对象不一定会调用构造方法.
    列如:在反序列化的时候,对象就没有调用构造方法


一. == 和 equals 方法的区别
            
            == 能用在基本类型数据之间,也可以用作引用类型的对象之间
            
                如果是俩个基本类型数字相比,  == 比较是基本类型的俩个数值是否相等
                
                如果是俩个引用类型的变量相比,== 比较是俩个引用所指向对象的内存地址值是否相等
    
                另外,==是java中的基本的操作符,我们无法改变==号的默认的比较方式。
            
            equals 只能用在俩个引用类型的对象之间
                这个方法是Object中定义的,所以对象直接或间接继承Object类之后,都可以使用这个继承过来的equals方法。
    
                在Object中,equals方法默认实现是这样的:
                    public boolean equals(Object obj) {
                        return (this == obj);
                    }
                那么就是意味着,如果调用的equlas方法是从父类Object中继承过来的(没有重写),那么这比较也是借助于 == 来比较俩个引用所指向的对象的内存地址值是否相等。
    
                如果我们不满意从Object继承过来的这个equals方法的默认实现,我们想用自己的方式来比较俩个对象是否相等,而不是比较俩个对象的内存地址值,例如我们希望使用对象中的属性来进行比较,如果俩个对象中的属性值都是一一对应相等的,那么我们就认为这个俩个对象是相等的,否则就是不相等。
    
                这个时候,我们就需要在子类中对继承过来的equals方法进行重写。


​                总结:==号是操作符,不能重写,equals是Object中的方法,子类里面可以重写,重写后按照自己的要求进行对比俩个对象是否相等。如果不重写,那么父类Object的equals方法默认实现其实也是用了==号来比较俩个对象是否相等。


二.包装类型
            在java中,有八种基本的数据类型,这八种基本类型只能表示一些最简单的数字,这些数字最小的在内存中占8位,最大占64位。这些都是简单的数字,不是对象,所以也不能用来调用方法或者属性。
    
            在java的API中,对这八种基本类型,又专门提供了类类型,目的就是为了分别把这八种基本类型的数据,包装成对应的类类型,这时候就变成对象了,就可以调用方法了或者访问属性了。
    
            这些类型,就称为基本类型所对应的包装类型。
    
            基本类型            包装类型
            boolean                Boolean
            byte                Byte
            short                Short
            int                    Integer
            long                Long
            float                Float
            double                Double
            char                Character

 

 

三. abstract修饰符
            abstract可以用来修饰类、方法,如果修饰类,那么这个类就是抽象类,如果修饰方法,那么这个方法就是抽象方法。
    
            抽象方法
                只有方法的声明,没有方法的实现,这样的方法就是抽象方法。
                例如:
                //这就是一个只有声明没有实现的方法
                public void test();
    
                //这样的方法需要使用abstract修饰符来修饰,说明它是一个抽象方法
                public abstract void test();


                //既有方法的声明,又有方法的实现
                public void test(){
                    System.out.println("hello");
                }
                
                //既有方法的声明,又有方法的实现,只不过这个方法的实现是一个空实现,也就是大括号中没有代码。但是这也算是方法的实现
                public void test(){
                    
                }


​            
​            抽象类
​                只要使用abstract修饰的类,就是一个抽象类
​    
​                例如:
​                //这是一个普通的类
​                public class Person{
​                
​                }
​    
​                //如果想把一个普通的类变为一个抽象类,只需要加一个修饰符即可 abstract
​                public abstract class Person{
​                
​                }
​    
                注意,普通类中能写什么样的代码,在抽象类中就可以写什么样的代码,没有什么区别,但过来,抽象类中能编写一种代码,普通类中就不可以编写,那就是抽象方法。
                抽象类中可以编写抽象方法,而普通类中不可以编写抽象方法。
                普通类中能够编写:
                    非静态
                        属性
                        方法
                        代码块(匿名代码块)
                        构造器
                    静态
                        属性
                        方法
                        代码块(静态代码块)
    
                抽象类中能够编写:
                    和普通类中编写的完全一致,额外还可以编写抽象方法。
                    但是也正是因为这个,抽象类不能被实例化,也就是不能直接使用new来创建对象。


​            
​            抽象类和抽象方法之间的关系
​                抽象类中可以有抽象方法,也可以没有抽象方法。
​                如果一个类中有抽象方法,那么这个类就必须要声明为抽象类。
​                (抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类)


            抽象类和抽象方法的特点
                抽象方法因为没有实现,所以是没有办法执行的,只有等这个方法实现以后,才能调用执行这个方法的实现代码。
    
                思考,这个抽象方法没有实现,肯定是不能执行的,但是否可以调用?
                    不能执行是因为没有实现的代码,但是可以进行调用,因为一个引用调用方法,最后会调用执行哪个对象中的方法,要看运行时这个引用所指向的对象是谁,以及对象中是否重写过这个方法。
    
                    方法的调用,是编译时,编译器要确定的,确定引用所调用的方法是哪一个类中的哪一个方法,最后执行的这个方法是哪一个对象中的,这个是运行时,JVM要确定的,主要是看这个引用指向对象是谁,以及对象中是否重写过该方法。


                抽象类因为代码里面【可能】会存在没有实现的抽象方法,所以我们是不能使用这个抽象类直接new对象的,假设抽象类中有抽象方法,我们new出了这个抽象类的对象,那么用这个对象调用类中的抽象方法,这个做法是没有意义,也是不符合语法要求的。所以语法层面上,根本就不允许我们创建抽象类的对象。


​            
​            抽象类和它的子类
​                抽象类不能直接使用new创建对象(也就是不能被实例化),但是抽象类可以被子类继承,将来可以使用子类创建对象,再结合java中的多态,可以使用父类的引用,指向子类对象,这时候这个父类就是这里说的抽象类了。
​                
​                子类中继承了父类,父类是一个抽象类,那么子类就必须把父类中的抽象方法给实现了,这里说的实现,语法上就是我们之前用的重写,但是从意义讲,用实现这个词来描述会更加合适一些。
​    
​                如果子类没有实现父类中的抽象方法,或者没全部把父类中的抽象方法给全部实现,那么这个子类也必须要声明为抽象类。因为抽象方法是可以被继承的,所以父类中假设有5个抽象方法,子类继承后,就相当于子类中有这5个抽象方法。


​            

            思考,静态方法是否可以声明为抽象的?
                //编译报错
                //错误信息:非法的修饰符组合: abstract和static
                public static abstract void say();
    
            思考,final修饰的方法是否可以声明为抽象的?
                //编译报错
                //错误信息:非法的修饰符组合: abstract和final
                public final abstract void say();
    
            总结:只要是不能重写的方法,都不能声明抽象方法,因为这些方法将来没有办法重写实现。
            注意,抽象方法,就是为了将来让子类中去重写实现的。抽象方法可以调用,但不能执行,调用之后将来执行的一定是这个抽象方法实现。
                (这个抽象方法的实现,在这个抽象类的子类中)
                (需要用到多态和重写)
    
            思考,静态方法是否可以使用final修饰?
                //编译通过
                //final和static的含义之间没有冲突
                public static final void say(){}

​            思考,抽象类既然不能直接new对象,那么抽象类中是否有构造器?
​                中的构造可以有构造器。普通类中能写什么属性、方法、构造器、代码块,那么抽象方法中就可以写什么属性、方法、构造器、代码块。
​                抽象类器,虽然不能直接使用它创建对象,但是可以在创建子类对象的时候,子类的构造器中会调用这个父类中的构造器。
​    
​            

```
思考,我们为什么要编写抽象方法?
                在一个类中实现方法时候,会遇到一些问题,通过思考分析后会发现,这个方法我们在这里是没有办法很合适的进行实现的,一般的原因会是当前这个类所表示的范围比较大,它的下面很多子类的情况各自不同,所以导致我们没办法在这个范围比较大的类中,很好的对这个方法进行实现,那么我们就可以把这个方法声明为抽象方法,然后将来在子类中对象这个方法进行重写实现,因为子类一般表示的范围比较小,情况比较具体,所以可以在子类中进行很好的实现。
                例如,Animal这个类,表示所有的动物,这个范围是非常大的,我们在Animal中,只能确定动物是可以跑的,有run这个方法,但是动物是用什么方法跑的,run方法如何写代码一步步的实现,在Animal类中是确定不了的。这时候就可以把run方法在Animal中声明为抽象方法,将来在一个具体的子类中再去实现这个run方法,例如可以Dog这个类中进行实现,因为Dog描述的狗这个类型,范围比较Animal小很多,所以就有可以具体描述出狗是怎么跑的,然后对run方法进行实现。
    
                在一个表示范围比较大的类中,定义了一个方法,在结合实际情况,从当前设计和意义的角度考虑后,发现这个方法在当前表示这么大一个范围的类中无法实现,所以接下来可以有俩种选择:
                    1.把这个方法写出抽象方法
                    2.把这个方法实现了,给一个默认的实现
```

            思考,我们为什么要编写抽象类?
                1. 抽象类中有抽象方法(绝大多数情况属于这种)
                    类中有抽象方法,那么这个类一定要声明为抽象类。
                2. 抽象类中没有抽象方法(比较少见)
                    第一种考虑的情况:
                        我们设计了一个类,由于某种原因,我们并不想别人直接使用这个类来new对象,我们希望别人使用子类继承这个类,然后再使用这个子类型。这时候就可以把这个类使用abstract修饰,变为一个抽象类,但是类中没有抽象方法
                    
                    第二种考虑的情况:
                        在一个抽象类中,本来有很多个抽象方法,例如有20个,那么将来这个抽象类的子类就必须把这个20抽象方法全都个实现了,但是很多少这个子类其实只需要使用到其实一俩个方法而已,由于语法的要求,不得已实现了这个20个方法,这种情况并不是很合适,所以这个时候可以考虑,把这20抽象方法全都给一个默认的实现,例如空实现。这时候就有了一个抽象类,但是类中没有抽象方法,将来的子类继承这个抽象类后,就可以用到哪一个方法,就只重写这个方法了。

 

       四. 接口(interface)
            
            1.接口和抽象类的区别
                抽象类也是类,除了可以编写抽象方法和不能直接new对象之外,其他地方和普通的类都是一样的。
    
                接口已经是另外一种类型,和类是有本质的区别的,所以不能使用类的相关标准/特点去衡量接口。
                    例如:类中都会有构造器,但是接口中没有构造器,因为它们本来就不是一个种类的。
                
                声明类的关键字是class,声明接口的关键字是interface
                    例如:
                    public class Person{}
                    public interface Action{}
    
                类或者抽象类可以被子类继承,并且是【单继承】
                    例如:类A继承了类B,这时候类A的对象就属于B类型,可以使用多态:一个父类的引用,指向子类对象
                        B b = new A();
                    
                    注意,继承使用的关键字为extends
    
                接口可以被类进行实现,并且是【多实现】
                    例如:类A可以同时实现接口B、C、D、E...,这时候类A的对象就属于B、C、D、E等类型了,可以使用多态:一个接口的引用,可以指向它的任意一个实现类对象。
                        B b = new A();
                        C c = new A();
                        D d = new A();
                        E e = new A();
                    
                    注意,这里使用不同类型的引用B C D E来指向A类的对象,它们区别在于,使用不同类型的引用的时候,我们所能调用到的方法是不一样的。
                        例如,B b = new A(); 引用b所能调用到的方法,只有B类型中定义的方法 和 Object中定义的方法。
                    注意,实现使用的关键字 implements
                    注意,一个类实现接口后,就把接口中的属性和方法都继承过来了,所以实现也是另外一种形式的继承。java中引入实现这种机制的目的,也是对继承的一种扩展。


​            
​            2. 接口中的方法必须是抽象方法
​                
​                接口中可以不写任何方法, 但是如果写了,那么必须是抽象方法。
​    
​                例如:
​                public interface Action{
​                    
​                    public abstract void run();
​    
​                    public void test();
​                    
                    //默认就是public abstract修饰
                    void say();
                
                }
    
                注意,只有在接口中,才可以省去public abstract这俩个关键字,在抽象类中,编写抽象方法的时候,这俩个关键字是不能省去的。


            3.接口中的属性必须是public static final修饰的
                接口中可以不写属性,但是如果写了那么就必须是公共的静态常量
    
                public interface Action{
                    
                    public static final String NAME = "tom";
                    //属性默认的修饰符就是public static final
                    int AGE = 20;
    
                }
    
                注意,只有在接口中,才可以省去public static final这俩个关键字,在抽象类中,编写公共的静态常量的时候,这三个关键字是不能省去的。


​            
​            4.接口中可以编写哪些代码
​                属性必须是public static final
​                属性默认是public static final
​    
​                方法必须是public abstract
​                方法默认是public abstract
​    
​                例如:
​                public interface Action{
​                    //public static final String NAME = "tom";
​                    //public abstract void test();
​                    
​                    //可以这样简写
​                    String NAME = "tom";
​                    void test();
​                }
​    
​                javap Action.class 看到的结果为:
​                //说明代码中我们虽然简写了,但是编译之后,会自动把这些默认的修饰符给加上来
​                public interface com.briup.day24.Action {
​                    public static final java.lang.String NAME;
​                    public abstract void test();
​                }
​    
                注意,如果代码中使用private或者protected修饰的属性或方法的话,那么编译会报错。


​                
​                注意,接口中还可以编写静态方法和默认方法,但是需要JDK1.8及以    上的支持。(目前先暂且不讨论这个,后面会专门的进行学习)
​                    例如:
​                    public interface Action{
​                        
​                        static void test(){
​                            //....
​                        }
​    
​                        default void say(){
​                            //....
​                        }
​    
​                    }


​                
​                注意,接口中不能编写匿名代码块,也不能编写静态代码块。
​    
​                注意,接口中也没有构造器


                总结:接口中只能写属性和方法,属性必须是公共的静态常量,方法必须是公共的抽象方法。(JDK1.8以上支持在接口中编写静态方法和默认方法)


            5.接口的使用
                
                一个类可以同时实现一个或者多个接口,如果有多个接口,那么需要使用逗号隔开。
    
                注意,一个类实现了一个接口,那么就相当于把接口中的属性和方法都继承过来了,因为接口中的方法都是抽象方法,所以实现类中就需要把这些方法都给实现了,否则这个类就需要声明为抽象类.(和继承一个抽象类的要求是一样的)
    
                注意,接口中可以有很多抽象方法,也可以没有任何抽象方法。
    
                注意,接口+多态 是java中,非常非常常见的使用方式。
                一个接口的引用,可以指向它的任何一个实现类对象。
    
                例如:
                public interface Action{
                    
                    public void doSomething();
                    public void test();
                
                }
    
                public interface Fly{
                    
                    public void fly();
                    public void test();
                }
    
                public class Student implements Action,Fly{
                    
                    public void doSomething(){
                        //..
                    }
    
                    public void fly(){
                        //..
                    }
                    
                    //既是对Action接口中test方法的实现
                    //也是对Fly接口中的test方法的实现
                    public void test(){
                    
                    }
    
                }
                
                main:
                    Action a = new Student();
                    a.doSomething();
                    
                    //因为变量a所属的类型Action中没有fly方法
                    //所以编译器报错
                    a.fly();
                    
                    //可以做类型转换,转为Fly类型,因为Fly类型中有fly方法,所以可以调用
                    //注意,在当前代码情况下,这句代码,编译通过,运行也没问题,虽然Fly和Action之间没有任何关系,但是类型转换还是成功,因为我们这里对象实现类型是Student,这个类同时实现了Fly和Action接口
                    //所以这个对象既属于Fly类型,又属于Action类型
                    Fly f = (Fly)a;
    
                    f.fly();

 

                注意,在代码中一定要是分清楚,当前引用的类型是什么,以及我们使用这个引用都可以调用到哪些方法。


​            
​            6. 一个接口可以继承多个父接口
​                
​                例如:
​                public class Student implements C{
​    
​                    public void testC(){}
​    
​                    public void testA(){}
​    
​                    public void testB(){}
​    
                }
    
                class StudentTest{
                    
                    public static void main(String[] args){
                        
                        C c = new Student();
                        
                        System.out.println(c instanceof A);
                        System.out.println(c instanceof B);
                        System.out.println(c instanceof C);
    
                    }
    
                }
    
                interface A{
                    public void testA();
                }
    
                interface B{
                    public void testB();
                }
    
                interface C extends A,B{
                    
                    public void testC();
    
                }

 

            7.接口的意义
                
                例如我们可以在完成功能之前,在接口中可以提前先定义出完成功能要使用到的相关方法,这里的方法都是抽象方法,也就是只有方法的声明, 没有方法的实现。
    
                同时接口也可以帮我们在一定程度上解决,类和类之间单继承的束缚,因为接口可以被多现实。
    
                在学习编程的过程中,我们会遇到很多规范、标准,在java中大多的规范、标准都是以接口的方式进行体现,因为类实现接口后,类中一定是有接口里面所声明的方法的实现,只有我们实现规范、标准中所提供的接口,那么我们的类中也一定会要这些方法,这时候我们的类其实也就是在按照这些规范、标准要的方式进行编写。

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值