JAVA基础知识点(易考点)总结(一)

针对JAVA基础以及常问知识点的总结

以下为问题目录

java中==和equals和hashCode的区别

String、StringBuffer、StringBuilder、StringTokenizer区别

int、char、long各占多少字节数

int与integer的区别

谈谈对java多态的理解

什么是内部类?内部类的作用

抽象类和接口区别

抽象类的意义

抽象类与接口的应用场景

抽象类是否可以没有方法和属性?

泛型中extends和super的区别

父类的静态方法能否被子类重写

进程和线程的区别

final,finally,finalize的区别

序列化的方式

Serializable 和Parcelable 的区别

静态内部类的设计意图

闭包和局部内部类的区别

string 转换成 integer的方式及原理


一、java中==和equals和hashCode的区别

==用于比较两个变量数值,或对应内存地址是否相等。

equals是Object类中提供的方法,其方法中直接使用==比较两对象,都是比较的引用,故对基本数据类型,与==相同。想要进行内容的比较的话可以进行方法重写。比如String类:

String s1 = new String("Hello");

String s1 = new String("Hello");

new了两个对象,对于==来说肯定是false的,对于equals来说,因为内容相同,所以返回true。

hashCode()也是Object类里面的方法,返回值是一个对象的哈希码(int值),如果没有重写hashCode()方法,任何对象的hashCode()方法都是不同的。用户一般调用的是equals,hashCode就比较少。在hashmap中,key是不可以重复的,这里的判断是否重复用了equals和hashCode,因此对于“不可重复”,两者只要一个不同即可。

因此,equals和hashCode的关系:

1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。

2、如果两个对象不equals,他们的hashcode有可能相等。

3、如果两个对象hashcode相等,他们不一定equals。

4、如果两个对象hashcode不相等,他们一定不equals。

另外,hashCode的返回是int型,比较起来不直观

问:覆盖equals方法时要注意什么?

答:同时也要覆盖hashCode方法,根据上面规则,否则会违反Object.hashCode的通用规定,从而导致该类无法与所有基于散列值的集合类(hashmap、hashset、hashtable)结合在一起正常运行。

二、String、StringBuffer、StringBuilder和StringTokenizer的区别

① String是final修饰的不可变类,对象一旦创建,其值不可改变,我们平时用String修改字符串其实是新建了对象,改变堆内存地址的指向。这样会产生很多无用对象,需要被垃圾回收器回收,因此影响性能。(浪费空间,影响性能)。而StringBuffer、StringBuilder是可变类。

②StringBuffer在初始化时,只能使用构造函数(StringBuffer s = new StringBuffer(“abc”);)的方式赋值。而String初始化可以用构造函数,也可以直接赋值(String s="abc";)

③StringBuffer和StringBuilder区别 : StringBuffer是线程安全的,而StringBuilder非线程安全,但是其执行效率更高。

④StringTokenizer是用来分隔字符串的工具类。

问1:String字符串修改原理?

答1:首先新建StringBuffer,其次调用append方法,最后调用toString将结果返回

问2:因此三者使用场景?

答2:(1)如果要操作少量的数据用 String;

(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;

(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。

三、int、char、long各占多少字节数

byte是存储空间的基本计量单位。1byte 存1个英文字母,2个byte存一个汉字。规定上是1个字节等于8位(1Byte = 8bit)。

四、int与integer的区别

1、Integer是int的包装类,int则是java的一种基本数据类型

2、Integer变量必须实例化后才能使用,而int变量不需要

3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值

4、Integer的默认值是null,int的默认值是0

拓展:

Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)

由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。

非new生成的Integer变量(Integer i =10;)和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)

对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false.(java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);)

public static Integer valueOf(int i){

    assert IntegerCache.high >= 127;

    if (i >= IntegerCache.low && i <= IntegerCache.high){

        return IntegerCache.cache[i + (-IntegerCache.low)];

    }

    return new Integer(i);

}

java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了.

因此对于在-128到127之间的integer,它们可以用"=="来比较,在范围之外的可以用"equal"来比较

五、谈谈对java多态的理解

多态分为两种

a. 编译时多态:方法的重载;

b. 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态。(我们平时说得多的事运行时多态,所以多态主要也是指运行时多态);

上述描述认为重载也是多态的一种表现,不过多态主要指运行时多态

运行时多态

a. 面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。

b. 多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

c. 实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

d. 多态的作用:消除类型之间的耦合关系。

多态存在的三个必要条件

一、要有继承;

二、要有重写;

三、父类引用指向子类对象。

实现机制(变现形式):重载(水平)和覆盖(垂直)

六、什么是内部类?内部类的作用

①什么是内部类:

将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。

②内部类的分类:

1、静态内部类

指被声明为static的内部类,他可以不依赖内部类而实例,而通常的内部类需要实例化外部类,从而实例化。静态内部类不可以有与外部类有相同的类名。不能访问外部类的普通成员变量,但是可以访问静态成员变量和静态方法(包括私有类型)

2、成员内部类

成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。

一个 静态内部类去掉static 就是成员内部类,他可以自由的引用外部类的属性和方法,无论是静态还是非静态。但是不可以有静态属性和方法、

3、局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

4、匿名内部类

匿名内部类就是没有名字的内部类,不使用关键字class、extends、implement关键字,无构造函数,需要继承其他类或实现其他接口。

③作用

1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,

2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

3.可以避免修改接口而实现同一个类中两种同名方法的调用。(继承和实现的类和借口中有同名方法)

4.代码更简洁、紧凑,但是可读性可能会下降。

七、抽象类和接口异同

相同点:

1.都含有抽象方法,不能被实例化

2.接口的实现类或者抽象类的子类都只有在实现了方法后才能被实例化

不同:

1.接口与类的区别:接口需要实现(通过implement),抽象类只能继承(extend用s)。一个类可以实现多个接口,但是只能继承一个类,通过接口可以间接达到多重继承的目的

2.接口只有定义,其方法不能直接在接口中实现。但是接口类可以。

3.接口强调特定功能的实现,设计理念为“has - a”关系,抽象类强调从属关系,为“is -a”关系。

4.接口中定义的成员变量默认为public static final  ,必须赋初值。其成员方法都是public、abstract修饰的。  抽象类中可以有自己的数据成员变量,也可以有非抽象方法。抽样类中成员变量默认为default(本包可见)。

因此,如果功能需要累加,用抽象类;不需要累加则用接口。

八、抽象类的定义

1,为子类提供一个公共的类型;

2,封装子类中重复内容(成员变量和方法);

3,定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。

九、抽象类与接口的应用场景

抽象类多用于在同类事物中有无法具体描述的方法的场景,所以当子父类之间有逻辑上的层次关系时,推荐使用抽象类;

接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或更多对象之间的特定交互活动时,应该使用接口。

接口(interface)的应用场合:

类与类之前需要特定的接口进行协调,而不在乎其如何实现。

作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。

需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。

需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。

抽象类(abstract class)的应用场合:

一句话,在既需要统一的接口,又需要实例变量或缺省的方法的情况下,就可以使用它。最常见的有:

定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。

某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。abstract的中介作用可以很好地满足这一点。

规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能

十、抽象类是否可以没有方法和属性?

抽象类中可以没有抽象方法,但有抽象方法的一定是抽象类。所以,java中 抽象类里面可以没有抽象方法。比如HttpServlet类。抽象类和普通类的区别就在于,抽象类不能被实例化,就是不能被new出来,即使抽象类里面没有抽象方法。

  抽象类的作用在于子类对其的继承和实现,也就是多态;而没有抽象方法的抽象类的存在价值在于:实例化了没有意义,因为类已经定义好了,不能改变其中的方法体,但是实例化出来的对象却满足不了要求,只有继承并重写了他的子类才能满足要求。所以才把它定义为没有抽象方法的抽象类

十一、泛型中extends和super的区别

上界通配符extends:泛型中extends的主要作用是设定类型通配符的上限。只能用于方法返回,告诉编译器此返参的类型的最小继承边界为T,T和T的父类都能接收,但是入参类型无法确定,只能接受null的传入

下界通配符super:泛型中super的主要作用是设定类型通配符的下限。只能用于限定方法入参,告诉编译器入参只能是T或其子类型,而返参只能用Object类接收

表示包括T在内的任何T的父类,表示包括T在内的任何T的子类

拓展:PECS

请记住PECS原则:生产者(Producer)使用extends,消费者(Consumer)使用super。

生产者使用extends

如果你需要一个列表提供T类型的元素(即你想从列表中读取T类型的元素),你需要把这个列表声明成,比如List,因此你不能往该列表中添加任何元素。

消费者使用super

如果需要一个列表使用T类型的元素(即你想把T类型的元素加入到列表中),你需要把这个列表声明成,比如List,因此你不能保证从中读取到的元素的类型。

即是生产者,也是消费者

如果一个列表即要生产,又要消费,你不能使用泛型通配符声明列表,比如List

十二、父类的静态方法能否被子类重写

不能,父类的静态方法能够被子类继承,但是不能够被子类重写,即使子类中的静态方法与父类中的静态方法完全一样,也是两个完全不同的方法。

十三、进程和线程的区别

进程是资源分配的最小单位,线程是程序执行(运算调度)的最小单位。

进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。

但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

十四、final,finally,finalize的区别

final用于声明属性方法和类,①对于final属性,该变量不可变,而且是引用的不可变,不关心指向对象内容的变化。必须初始化。②final方法,不允许任何子类重写该方法。③final类,不能被继承,所有方法不能被重写。

finally:作为异常处理的一部分,只用于try/catch语句中,并且附带一个语句块,代表这段语句最终一定会被执行,经常被用在需要释放资源的情况下。

finaliza是Object的一个方法,在垃圾回收器执行时会调用回收对象的finalize()方法,可以覆盖此方法来实现对其他资源的回收,例如关闭文件。(一旦准备好释放对象占有的空间,会首先调用finalize方法,并在下一次垃圾回收动作发生时,才会真正回收对象占用的内存)

十五、序列化的方式

两种对象持久化方式:序列化和内外部序列化。

(1)序列化

a 含义:在分布式系统中,在进行远程通信过程中,无论是任何数据类型,都是以二进制序列形式在网络上传送。序列化就是一种将对象以一连串的字节描述的过程,用于解决在对对象流进行读写操作时的问题。

b 实现序列化:类要实现Serializable接口。使用一个输出流构造一个对象流对象,紧接着,使用该对象的writeObject(Object obj)方法就可以将obj对象写出(保存其状态),要恢复时刻使用其对应输出流。

c 序列化的特点:

如果一个类能被序列化,其子类也可以

static代表类的成员,transient代表对象的临时数据,因此被声明为这两种类型的数据成员是不能被序列化的

d 使用场景:

使用序列化会影响系统的性能,若非必须尽量不用。以下情况需要使用:

需要用网络来发送对象,或对象的状态需要被持久化倒数据库或文件中

序列化可以实现深复制,即可以复制引用的对象

(2)外部序列化

外部序列化与序列化的区别是序列化是内置的API,只需要实现Serilizable接口即可。而外部序列化,Externalizable接口中的读写方法必须由开发人员实现,因此编写难度更大,但是更灵活,可能会提高性能。

拓展:

问:在用Serializable接口实现序列化时,类中所有属性都会被实例化,那么怎么实现部分属性序列化??

答:一、实现Externnalizable接口,可用readExternal和 writeExternal来控制序列化和反序列化的属性    二、使用transient关键字指定不被序列化的属性。

十六、Serializable 和Parcelable 的区别

Serializable 是Java序列化技术,其方式简单,只要类实现下该接口,然后增加一个唯一个序列化id: private static final long serialVersionUID = 1L; 默认方式最好直接设置为1L,因为java  sdk会自动进行hash计算,并生成唯一的UID值。

Parcelable是android特有的序列化API,它的出现是为了解决Serializable在序列化的过程中消耗资源严重的问题,但是因为本身使用需要手动处理序列化和反序列化过程,会与具体的代码绑定,使用较为繁琐,一般只获取内存数据的时候使用。

        1.在使用内存的时候Parcelable比Serializable的性能高。

        2.Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC(内存回收)。

        3.Parcelable不能使用在将对象存储在磁盘上这种情况,因为在外界的变化下Parcelable不能很好的保证数据的持续性。

你可能感兴趣的:(JAVA基础知识点(易考点)总结(一))