相信每次面试之前,大家都会大量刷一下面试题来应该对各种公司的面试吧,下面整理一下android方面的面试题分享给大家。
本文主要分为以下几部分:
==(双等号):对于基本数据类型(byte、short、char、int、long、float、double、boolean)来说,比较的是他们的值;对于引用类型(各种new出来的对象)来说比较的是他们的地址。
equals:默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法是判断对象的内存地址。一般地都是覆盖这个方法,根据对象的内容是否相等来判断对象是否相等。如:String类就是覆盖这个方法,先判断对象的内存地址是否相等,之后再判断内容是否相等。
hascode:hascode()方法返回的就是一个数值,其目的是生成一个hash码,hash码的主要用途就是在对对象进行散列的时候作为key输入,我们需要每个对象的hash码尽可能不同,这样才能保证散列的存取性能。
在java中一般的equals()和hascode()通常要遵从如下几点约定,这样才能保证这两个方法在java中的一个规范,这也是为什么重写equals()方法需要重写hascode()方法的原因:
int占4个字节、char占2个字节、long占8个字节。
int是基本数据类型,直接存数据。而integer是对象,用一个引用指向这个对象,是int的封装类。
多态是指:父类引用指向子类对象,在执行期间会根据引用对象的实际类型,调用具体对象的相应方法。
一般可以通过两种方式实现多态:重写、重载。
实现多态的三要素:集成、重写、父类引用指向子类对象。
String:
StringBuffer:
StringBuilder:
什么是内部类:
将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
作用:
接口的应用场景:
抽象类的应用场景:
泛型中extends主要作用是类型的设定上界通配符, extends T>对应的为T及其子类对象;
泛型中super与extends是完全相反的,其定义是下界通配符, super T>对应的为T及其子类对象;
不能。父类的静态方法能够被子类继承,但是不能够被子类重写,即使子类中的静态方法与父类中的静态方法完全一样,也是两个完全不同的方法。对于静态方法和静态变量来说,虽然在代码中可以通过子类对象来调用,当时在编译的时候就将其与类绑定在一起,既然它们在编译的时候就决定了调用的方法、变量,那就和重写没有关系了。重写指的是根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。
final:
在java中,final可以用来修饰类,方法和变量(成员变量或局部变量)。
finally:
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常,哪怕有return语句,都会执行),经常被用在需要释放资源的情况下。
finalize
finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。
特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。
一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。 所以,推荐不要使用finalize()方法,它跟析构函数不一样。
堆:是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
栈:是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread safe的。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。
1、平台区别
2、编写上的区别
3、选择的原则
4、本质的区别
可以继承、不能重载;
原因:
因为静态属性、方法从程序开始运行后就已经分配了内存。所有通过对象来访问该属性、方法的方式,都会在编译的时候就将其与类绑定在一起,就决定了调用的方法、变量,对象无关。
闭包:是能获取其他函数内部变量的函数。是一种能被调用的对象,它保存了创建它的作用域的信息。JAVA并不能显式地支持闭包,但是在JAVA中,闭包可以通过“接口+内部类”来实现。
局部内部类:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
integer.parseInt(string str)方法调用Integer内部的parseInt(string str,10)方法,默认基数为10,parseInt内部首先判断字符串是否包含符号(-或者+),则对相应的negative和limit进行赋值,然后再循环字符串,对单个char进行数值计算Character.digit(char ch, int radix)在这个方法中,函数肯定进入到0-9字符的判断(相对于string转换到int),否则会抛出异常,数字就是如上面进行拼接然后生成的int类型数值。
常见的一些字符编码方式无非有:ASCII、拓展ASCII编码、Unicode编码集、GBK/GB2312/GB18030、UTF-8;
UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。UTF-8的编码规则很简单,只有两条:
少数是汉字每个占用3个字节,多数占用4个字节。int类型在java中占4个字节。
java中实现多态的机制是依靠父类或接口的引用指向子类。从而实现了一个对象多种形态的特性。其中父类的引用是在程序运行时动态的指向具体的实例,调用该引用的方法时,不是根据引用变量的类型中定义的方法来运行,而是根据具体的实例的方法。
依赖注入也叫依赖倒转原则,是java设计理论中一条非常著名的原则。其核心思想就是要将这种具体类之间的依赖,尽量转换成抽象依赖,也就是说类A应该依赖于抽象类IB,而不是具体的类B。这个注入的过程,通常是由一个控制程序来完成的,无需对象去关心,举例如下:
Public Person{
private ICar car;
public Person(ICar onecar){
car=onecar;
}
public void drive(){
car.挂档;
car.踩油门;
car.打方向;
}
}
这个时候,进行注入并且调用的过程,就很简单了,如下:
Car car=new Car ();
Person boy=new Person(car);
boy.drive();
其实Java中的泛型是伪泛型,在编译期间,所有的泛型信息都会被擦除掉。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的List和List等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。
可以通过两个简单的例子,来证明java泛型的类型擦除:
ArrayList array1=new ArrayList();
array1.add("aaaa");
ArrayList array2=new ArrayList();
array2.add(10);
System.out.println(array1.getClass()==array2.getClass());
我们通过array1对象和array2对象的getClass方法获取它们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下了原始类型。
ArrayList arrayList3=new ArrayList();
arrayList3.add(1);//这样调用add方法只能存储整形,因为泛型类型的实例为Integer
arrayList3.getClass().getMethod("add", Object.class).invoke(arrayList3, "asd");
for (int i=0;i
当我们利用反射调用add方法的时候,却可以存储字符串。这说明了Integer泛型实例在编译之后被擦除了,只保留了原始类型。
字符串常量池的需要
字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。 假若字符串对象允许改变,那么将会导致各种逻辑错误,比如改变一个对象会影响到另一个独立对象。严格来说,这种常量池的思想,是一种优化手段。
允许String对象缓存HashCode
Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码。
安全性
String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。
因为当把Object对象放到集合中时,通过equals比较对象,不做处理还是会出现重复的问题,根据hash原则,对象的映射地址是根据算法生成,因为hash碰撞的存在,即两个不同的对象hash地址可能一样的情况,这样在hash地址相等的情况下还需要去重写equal方法进行比较。有两种办法可以解决这个问题,第一个就是重写Object类的equal和hashCode方法;第二个就是把对象转换成String再放入集合中,因为String类源码已经重写了这两个方法。