小言_互联网的博客

Java笔记梳理(四)查漏补缺-[类和对象]

324人阅读  评论(0)

        来换换脑子,这段时间一直瞎琢磨,琢磨这个,琢磨哪个,搞得头蒙,FastDFS告一段落。本片文章主要还是梳理Java基础查漏补缺,记录下一我之前没有遇到或者是忘了的东西。

========== 【局部代码块、构造代码块、静态代码块】==========

局部代码块

        定义:在方法里面的代码块,通常用于控制变量的作用范围,出了括号就失效,变量的范围越小越好,成员变量会有线程安全问题
        表现形式:没有固定表现形式,说白了就是方法体中的代码。

构造代码块

        定义:存在于类的内部,方法的外部的代码块,通常用来抽取构造方法中的共性代码。构造代码块会在构造方法之前加载。每次调用构造方法前都会调用构造代码块。
        表现形式:{语句1;语句2;…} //有点像静态代码块不过没有static

静态代码块

        定义:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
        表现形式:static {语句1;语句2;…} //是不是有点像

总结:
        说一下他们的执行顺序啊,局部代码块没什么好说的,就是方法中的代码块,在方法被调用时才会执行。
另外两个在同一个类中,执行顺序为静态代码块最先执行,其次是构造代码块,接着是构造函数。

========== 【this和super的区别】 ==========

        1、this代表本类对象的引用,super代表父类对象的引用。
        2、this用于区分局部变量和成员变量
        3、super用于区分本类变量和父类变量
        4、this.成员变量 this.成员方法() this(【参数】)代表调用本类内容
        5、super.成员变量 super.成员方法() super(【参数】),代表调用父类内容
        6、this()和super()不可以同时出现在同一个构造方法里。
说明:为什么this()和super()不能出现在同一个构造方法中
        原因很简单,因为this()出现在构造函数中代表调用本类中的构造方法,而super出现在构造方法中代表调用父类的构造方法,如果两个同时出现,会报一个编译错误:Constructor call must be the first statement in a constructor意思是,构造函数调用必须是构造函数中的第一个语句,因此,两者都是调用构造函数的话,是无法同时出现的。

========== 【重写和重载的区别】 ==========

        1、重载:是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
        2、重写:是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型
        3、重写是父类与子类之间多态性的一种表现
        4、重载是一类中多态性的一种表现

========== 【向上转型和向下转型】 ==========

        在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
        在应用中存在着两种转型方式,分别是:向上转型和向下转型。

向上转型

        向上转型:父类的引用指向子类对象Parent p=new Child();
        说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类的方法就根据这个引用指向调用子类重写方法。

向下转型

        向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。
                Parent p = new Child();//向上转型,此时,p是Parent类型
                Child c = (Child)p;//此时,把Parent类型的p转成小类型Child,向下转型
        //其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
        说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能

========== 【静态变量和实例变量的区别 ==========

        在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
        在程序运行时的区别:
                1.实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变
        量。
                2.静态变量不属于某个实例对象,而是属于类,所以也称为类变量
                3.只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。而
        实例变量必须在类被实例化为对象后才会被分配空间。
                4.实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

========== 【abstract注意事项 】==========

        抽象方法要求子类继承后必须重写。以下关键字不可以和abstract关键字一起使用。也不是绝对的不可以使用,只是,用是可以用的,只是没有意义了。
        1、private:被私有化后,子类无法重写,与abstract相违背。
        2、static:静态的,优先于对象存在。而abstract是对象间的关系,存在加载顺序问题。
        3、final:被final修饰后,无法重写,与abstract相违背。

========== 【抽象类和接口的区别】 ==========

        1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
        2、抽象类要被子类继承,接口要被类实现。
        3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
        4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
        5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
        6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
        7、抽象类里可以没有抽象方法
        8、如果一个类里有抽象方法,那么这个类只能是抽象类
        9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
        10、接口可继承接口,并可多继承接口,但类只能单继承。
说明:标蓝色的第三点说法,在jdk1.8之后已经不再适用,jdk1.8中接口新增了default关键字的使用,通过default关键字,可以允许接口中的方法有默认的实现。

==========【“ == ”和equals的区别】 ==========

        1、当使用= =比较时,如果相比较的两个变量是引用类型,那么比较的是两者的物理地址(内存地址),如果相比较的两个变量都是数值类型,那么比较的是具体数值是否相等。
        2、当使用equals()方法进行比较时,比较的结果实际上取决于equals()方法的具体实现
        说明:任何类都继承自Object类,因此所有的类均具有Object类的特性,比如String、integer等,他们在自己的类中重写了equals()方法,此时他们进行的是数值的比较,而在Object类的默认实现中,equals()方法的底层是通过==来实现的。

==========【String、StringBuilder和StringBuffer的特点和区别】 ==========

        最后来说一个经常经常经常会问的面试题吧,这才是今天我想记录的重要的一个内容。以前总被问到,总是说不清楚。先一个一个来说。

String

        特点:是一个封装了char类型数组的对象。同时是被final修饰的不可变的。
        我们查看源码可以知道,String这个类底层使用char类型的数组来存放对象的。另外,String还有一个特性就是字符串不可变,字符串不可变体现在两个方面,一个是String类是被final关键字修饰的,另外一个就是String类底层的char类型数组也是被final修饰的。
        先说String类被final修饰:String类被final修饰意味着String不可被继承,String类是不会有子类的,String类中的属性或方法也不会被修改。也不会产生因为继承可能会产生类爆炸等问题。因此,String类的不可变带来的好处就是安全,假如所有的线程都共同使用这一个对象的实例,而这个对象又是不可变的,所以就不用考虑线程安全的问题了。
        再来说说char类型数组被final修饰,char数组被final修饰意味着这个数组一旦被赋值就不可被修改,因此,我们每次在给String类型的变量重新赋一个不一样的值时,都是新开辟了一块内存空间,指向了另外一个内存地址,并不会修改原来的内容。而且每次我们创建String对象并赋值时,这个值都被存放在一个常量池中,如果下次访问的是相同的内容,会直接访问常量池中的对象。这就是字符串共享,这样的设计,减少了String对象被创建的次数,大大降低了内存的消耗,提高了性能。而要实现字符串的共享,那字符串必然要被设计为不可变的,不然随随便便的就被修改了,因为假设字符串是可变的,好多个线程大家都在在使用字符串a,而这个时候突然跑过来一个线程2修改了字符串,那产生的后果是不可想象的,因此,这也是为什么char数组被设置成final的原因的,因为final代表者不可修改,禁止修改。
        总结:String为什么被设计为final。
        1.安全性
        2.提高性能,降低内存消耗

StringBuilder/StringBuffer

        由于这俩货是在是太像了,也有很多相同的方法。甚至连方法名都是一样的。
        特点:底层封装的都是char类型数组,都是字符串可变。
        依旧从源码中看,我们看以从无参构造函数中看到char类型数组的默认长度是16,如果传入的字符串长度超过16的,会自动扩容至原来的长度的2倍在加2(int newCapacity = value.length * 2 + 2;),而且它们提供了专门用于字符串拼接的方法append方法。由于是字符串可变,它们也提供了修改字符串的方法。

总结:三者的区别

        String:底层封装char类型数组,字符串不可变,不可被继承,字符串拼接效率很低。线程安全,性能好。
        StringBuilder:jdk1.5后产生,底层封装char类型数组,字符串可变,可以被继承,字符串拼接效率高。线程不安全。
        StringBuffer:旧版本提供的,底层封装char类型数组,字符串可变,可以被继承,字符串拼接效率高。线程安全。它的线程安全是因为每一个方法都被synchronized关键字修饰。
        在执行效率上:StringBuilder >StringBuffer >String。


转载:https://blog.csdn.net/qq_39185919/article/details/101022310
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场