1. equals和hashCode的区别
equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值
hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable。
两个obj,如果equals()相等,hashCode()一定相等。
两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。
所以: 可以考虑在集合中,判断两个对象是否相等的规则是:
第一步,如果hashCode()相等,则查看第二步,否则不相等;
第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等
1、 首先equals()和hashcode()这两个方法都是从object类中继承过来的。
equals()是对两个对象的地址值进行的比较(即比较引用是否相同)。
hashCode()是一个本地方法,它的实现是根据本地机器相关的。
2. int、char、long各占多少字节数
Java基本类型占用的字节数:
1字节: byte ,boolean
2字节: short ,char
4字节: int ,float
8字节: long ,double
注:1字节(byte)=8位(bits)
3. Integer和int的区别
1、Integer是int提供的封装类,而int是Java的基本数据类型;
2、Integer默认值是null,而int默认值是0;
3、声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;
4、Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。
4.探探对java多态的理解
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
比方说按下 F1键这个动作,如果当前在 Word 下弹出的就是 Word 帮助;在Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String
5.String、StringBuffer、StringBuilder区别
String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例:
1 Stringstr="abc";
2System.out.println(str);
3str=str+"de";
4System.out.println(str);
如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
总结一下
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
6.什么是内部类?内部类的作用
内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类
问:那为什么要将一个类定义在另一个类里面呢?清清爽爽的独立的一个类多好啊!!
答:内部类的主要作用如下:
1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类
2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据
3. 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便
7抽象类和接口区别
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。
人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.
所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。
第一点.接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。
第二点.接口可以多继承,抽象类不行
第三点.接口定义方法,不能实现,而抽象类可以实现部分方法。
第四点.接口中基本数据类型为static 而抽类象不是的。
当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。
1、相同点
A. 两者都是抽象类,都不能实例化。
B. interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。
2.、不同点
A. interface需要实现,要用implements,而abstract class需要继承,要用extends。
B. 一个类可以实现多个interface,但一个类只能继承一个abstract class。
C. interface强调特定功能的实现,而abstract class强调所属关系。
D. 尽管interface实现类及abstrctclass的子类都必须要实现相应的抽象方法,但实现的形式不同。interface中的每一个方法都是抽象方法,都只是声明的(declaration, 没有方法体),实现类必须要实现。而abstract class的子类可以有选择地实现。
8.抽象类是否可以没有方法和属性?
抽象类可以不含抽象方法但是含抽象方法的类一定是抽象类(或者接口)
② java允许类、接口或者成员方法具有抽象属性,但不允许成员域或构造方法具有抽象属性
②如果一个类不具有抽象属性,则不能在该类的类体中定义抽象成员方法
9. 接口的意义
1、重要性:在Java语言中, abstractclass 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。
2、简单、规范性:如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。
3、维护、拓展性:比如你要做一个画板程序,其中里面有一个面板类,主要负责绘画功能,然后你就这样定义了这个类。
可是在不久将来,你突然发现这个类满足不了你了,然后你又要重新设计这个类,更糟糕是你可能要放弃这个类,那么其他地方可能有引用他,这样修改起来很麻烦。 如果你一开始定义一个接口,把绘制功能放在接口里,然后定义类时实现这个接口,然后你只要用这个接口去引用实现它的类就行了,以后要换的话只不过是引用另一个类而已,这样就达到维护、拓展的方便性。
4、安全、严密性:接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些(一般软件服务商考虑的比较多)
10.泛型中extends和super的区别
首先解释两个概念:Java中的通配符和边界
通配符:“?”就是一个占位符,它不表示任何具体的类型,而是表示符合定义规则的一个或者多个类型的一个占位标志
边界:
<? extends T> 表示上界通配符 它表示T以及T的子类, 类型最高是T
<? super T> 表示下界通配符 它表示T以及T的超类,类型最高可到Object,最低是T
<? extends T> 表示上界通配符 它表示T以及T的子类, 类型最高是T。
<? super T> 下界通配符: 表示T以及T的超类,可以存数据,但是只能取出Object的数据
// compile error
// List <? extends Fruit> appList2 =new ArrayList();
// appList2.add(new Fruit());
// appList2.add(new Apple());
// appList2.add(new RedApple());
List <? super Fruit> appList = newArrayList();
appList.add(new Fruit());
appList.add(new Apple());
appList.add(new RedApple());
<? extends T> 表示上界通配符 它表示T以及T的子类, 类型最高是T
为什么上述问题中使用上界通配符后就出现编译出错的问题:
List<? extends Fruit> list 表示当前列表中可以存储Fruit以及Fruit的子类,从这层含义来看,似乎上述不应该报错,因为存储的对象是符合list定义限定数据范围的。但是事实上确实报错了,这主要是Java出于泛型安全性的考虑。因为上界通配符<? extends T> 表示的是一个类型范围,编译器无法确定List所持有的具体类型,所以无法安全的向其中添加对象。但是可以添加null,因为null
可以表示任何类型。所以List的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List<Apple> 赋值。因此对于上界边界符,Java编译器限制了其存数据。即:<? extends T> 不能存数据,但是可以取数据,而使用get方法取出来的数据只能赋值为T类型的变量。T
如:
List<? super apple> list = newArrayList<fruit>();;
list.add(new apple());
list.add(new redApple());
// list.add(new fruit()); 此处编译报错,
出错分析:
因为list的定义限定存储数据的类型最低是apple,因此对于编译器来说,只有存入低于或者等于apple的数据对象才能认为是数据安全的。所以存入fruit对象时才会报错。
11.父类的静态方法能否被子类重写
不能
public class A extends B{
public static void f() {
System.out.println("com.sdkd.A.f()");
}
public static void main(String[] args) {
A.f();
}
}
class B {
public static void f() {
System.out.println("com.sdkd.B.f()");
}
}
输出结果:com.sdkd.A.f()
子类不能重写实例方法
父类的静态方法被绑定了[写死了orz…],不能重写
解析过程:
类方法和接口方法引用的常量类型定义是分开的,如果在类的方法表中发现class_index 索引的C是个接口,那就直接抛出java.lang.IncompatibleClassChangeError异常
如果通过了第一步,在类中查找是否有简单名称和描述符都与目标匹配的方法,如果有则返回这个方法的直接引用,查找结束
否则,在类的父类中递归查找是否有简单名称和描述符都与目标匹配的方法,如果有则返回这个方法的直接引用,查找结束
否则,在类实现的接口列表及父接口中递归查找是否有简单名称和描述符都与目标匹配的方法,如果有则返回这个方法的直接引用,查找结束
否则,宣告方法查找失败,抛出java.lang.NoSuchMethodError
12.进程和线程的区别
(1)进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元
(2)同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程。
(3)进程的创建调用fork或者vfork,而线程的创建调用pthread_create,进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束
(4)线程是轻量级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的
(5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源
(6)线程有自己的私有属性TCB,线程id,寄存器、硬件上下文,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标识一个进程或一个线程的标志
13. final,finally,finalize的区别
Final用于修饰类、成员变量和成员方法。final修饰的类,不能被继承(String、StringBuilder、StringBuffer、Math,不可变类),其中所有的方法都不能被重写,所以不能同时用abstract和final修饰类(abstract修饰的类是抽象类,抽象类是用于被子类继承的,和final起相反的作用);Final修饰的方法不能被重写,但是子类可以用父类中final修饰的方法;Final修饰的成员变量是不可变的,如果成员变量是基本数据类型,初始化之后成员变量的值不能被改变,如果成员变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象,但是对象当中的内容是允许改变的。
Finally通常和try catch搭配使用,保证不管有没有发生异常,资源都能够被释放(释放连接、关闭IO流)。
Finalize是object类中的一个方法,子类可以重写finalize()方法实现对资源的回收。垃圾回收只负责回收内存,并不负责资源的回收,资源回收要由程序员完成,Java虚拟机在垃圾回收之前会先调用垃圾对象的finalize方法用于使对象释放资源(如关闭连接、关闭文件),之后才进行垃圾回收,这个方法一般不会显示的调用,在垃圾回收时垃圾回收器会主动调用。
14.序列化的方式
序列化是将对象状态转换为可保持或传输的格式的过程。说明白点就是你可以用对象输出流输出到文件.如果不序列化输出的话.很可能会乱!
实现方式是实现java.io.Serializable接口.这个接口不需要实现任何具体方法.只要implements java.io.Serializable 就好了
java中的序列化机制能够将一个实例对象(只序列化对象的属性值,而不会去序列化什么所谓的方法。)的状态信息写入到一个字节流中使其可以通过socket进行传输、或者持久化到存储数据库或文件系统中;然后在需要的时候通过字节流中的信息来重构一个相同的对象。
一般而言,要使得一个类可以序列化,只需简单实现java.io.Serializable接口即可。
15. Serializable 和Parcelable 的区别
两种都是用于支持序列化、反序列化话操作,两者最大的区别在于存储媒介的不同,Serializable使用IO读写存储在硬盘上,而Parcelable是直接在内存中读写,很明显内存的读写速度通常大于IO读写,所以在Android中通常优先选择Parcelable。
16.静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?
java中静态属性和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏.
原因:
1).静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成对,不需要继承机制及可以调用。如果子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。如果你想要调用父类的静态方法和属性,直接通过父类名.方法或变量名完成,至于是否继承一说,子类是有继承静态方法和属性,但是跟实例方法和属性不太一样,存在"隐藏"的这种情况。
2).多态之所以能够实现依赖于继承、接口和重写、重载(继承和重写最为关键)。有了继承和重写就可以实现父类的引用指向不同子类的对象。重写的功能是:"重写"后子类的优先级要高于父类的优先级,但是“隐藏”是没有这个优先级之分的。
3). 静态属性、静态方法和非静态的属性都可以被继承和隐藏而不能被重写,因此不能实现多态,不能实现父类的引用可以指向不同子类的对象。非静态方法可以被继承和重写,因此可以实现多态。
15.静态内部类的设计意图
我们知道,在java中类是单继承的,一个类只能继承另一个具体类或抽象类(可以实现多个接口)。这种设计的目的是因为在多继承中,当多个父类中有重复的属性或者方法时,子类的调用结果会含糊不清,因此用了单继承。
而使用内部类的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整
16. 成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用
成员内部类是最普通的内部类,它的定义为位于另一个类的内部
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护
17.闭包和局部内部类的区别
在JAVA中,闭包是通过“接口+内部类”实现
内部类:顾名思义,内部类就是将一个类定义在另一个类的内部。在JAVA中,内部类可以访问到外围类的变量、方法或者其它内部类等所有成员,即使它被定义成private了,但是外部类不能访问内部类中的变量。这样通过内部类就可以提供一种代码隐藏和代码组织的机制,并且这些被组织的代码段还可以自由的访问到包含该内部类的外围上下文环境。
18.单例模式
/**
* 饿汉模式
* 与懒汉模式相比:加载类时比较慢,因为在加载类时就创建了实例,但运行时获取对象的速度比较快,饿汉模式是线程安全的
* Created byluyy on 2016/6/20.
*/
public classSiglelation {
//1.将构造方法私有化,不允许外部直接创建对象
private Siglelation(){
}
//2.创建类的唯一实例,使用 private static 修饰
private static Siglelation siglelation=new Siglelation();//加载类时加载静态变量与方法的方式叫做饿汉模式
//3.提供一个用于获取实例的方法,使用public static修饰
public static Siglelation getSiglelation() {
return siglelation;
}
}
packageorg.xdemo.example.websocket.test.single;
/**
* 懒汉模式
* 与饿汉模式相比:加载类时比较快,但是在运行时获取对象时速度相对较慢,懒汉模式是线程不安全的
* Created byluyy on 2016/6/20.
*/
public classSiglelation2 {
//1.将构造方法私有化,不允许外部直接创建对象
private Siglelation2(){
}
//2.声明的一实例,使用 private static 修饰
private static Siglelation2 siglelation;
//3.提供一个用于获取实例的方法,使用public static修饰
public static Siglelation2 getSiglelation() {
if(siglelation==null)
siglelation=new Siglelation2();
return siglelation;
}
}