常规面试题-1.基础知识

来源:互联网 发布:青花大罐淘宝 编辑:程序博客网 时间:2024/06/07 17:48

1.String 、StringBuffer 和 StringBuilder

String是不可变类,也就是说String一旦被创建,其值不能改变。由于String是不可变类,因此适合在要被共享的场合使用StringBuffer和StringBuilder是可变类,而当一个字符串经常需要被修改时,最好用StringBuffer和StringBuilder实现。StringBuilder不是线程安全的,StringBuffer是线程安全的。

String
1、String 类是一个final 修饰的类所以这个类是不能继承的,也就没有子类。
2、String 类的成员变量都是final类型的并且没有提供任何方法可以来修改引用变量所引用的对象的内容,所以一旦这个对象被创建并且成员变量初始化后这个对象就不能再改变了,所以说String 对象是一个不可变对象。
3、使用“+”连接字符串的过程产生了很多String 对象和StringBuffer 对象所以效率相比直接使用StringBuffer 对象的append() 方法来连接字符效率低很多。
4、引用变量是存在java虚拟机栈内存中的,它里面存放的不是对象,而是对象的地址或句柄地址。
5、对象是存在java heap(堆内存)中的值
6、引用变量的值改变指的是栈内存中的这个引用变量的值的改变是,对象地址的改变或句柄地址的改变,而对象的改变指的是存放在Java heap(堆内存)中的对象内容的改变和引用变量的地址和句柄没有关系。

StringBuffer (容器拓展也是同样机制,数组的扩容)
1、StringBuffer 类被final 修饰所以不能继承没有子类
2、StringBuffer 对象是可变对象,因为父类的 value [] char 没有被final修饰所以可以进行引用的改变,而且还提供了方法可以修改被引用对象的内容即修改了数组内容。
3、在使用StringBuffer对象的时候尽量指定大小这样会减少扩容的次数,也就是会减少创建字符数组对象的次数和数据复制的次数,当然效率也会提升。

2.“==”,equal和hashCode的区别

1.”==” 运算符用来比较两个变量的值是否相等。
如果两个变量是基本数据类型,可以直接使用“==”运算符来比较相对应的值是否相等。
如果两个变量是对象类型变量,那么比较的是两个变量是否指向同一个对象。
2.“equals”是Object类提供的方法之一。每一个JAVA类都继承自Object类,所以每一个对象都有equals这个方法。Object中equals(Object)方法时直接使用“==”运算符来比较两个对象的,所以没有覆盖equals(Object)方法的情况下,equals(Object)与“==”运算比较符一样,比较的是引用。
例如“String”类的equals方法是用于比较两个独立对象的内容是否相同。
3.hashCode()方法时从Object类中继承过来的,它可以用来坚定两个对象是否相等。Object类中的hashCode方法返回对象在内存中地址转换成int值,所以如果没有重写hashCode()方法,任何对象的hashCode()方法都是不相等的。
一般来说覆盖equals()方法也要覆盖hashCode()方法,否则就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值得集合类结合在一起正常工作。
hashCode()返回值和equals()方法关系如下:如果x.equals(y)返回true,即两个对象根据equals方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode()方法都必须产生同样的整数结果。如果x.equals(y)返回false,即两个对象根据equals()方法比较是不相等的,那么x和y可能有相同的hashCode()。
Effective JAVA中介绍了一种经典的HashCode算法:
[1]把某个非零常数值,例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int);
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c;
[4]返回result。

3.Java程序初始化顺序

Java程序初始化一般遵循3个原则(优先级依次递减):
1.静态对象(变量)优先于静态对象(变量)初始化,其中静态对象(变量)只初始化一次,而非静态对象(变量)可能会初始化多次。
2.父类优先于子类进行初始化。
3.按照成员变量的定义顺序进行初始化,即使变量定义散布于方法定义之中,它们依然在任何方法(包括构造函数)被调用前先初始化。

4. 为什么Java中有些接口没有任何方法

接口中的所有方法都是抽象的。接口中成员的作用域的修饰符都是public,接口中的常量值默认使用public static final修饰符,由于一个类可以实现多个接口,因此通常可以采用实现多个接口的方式来间接达到多重继承。
没有任何方法声明的接口被叫做标识接口,标识接口对实现它的类没有任何语义上的要求,它仅仅是充当一个标识的作用,用来表明实现它的类属于一个特定的类型。Java中已存在的标识接口有Cloneable和Serializable等,在使用时经常用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。

5.Java中clone()方法有什么作用

Java在处理基本数据类型(例如int,char,double等)时,都是采用按值传递(传递的是输入参数的复制)的方式执行,除此之外的其他类型都是按引用传递(传递的是对象的一个引用)的方式执行。
对象除了在函数调用时是引用传递,在使用“=”赋值时也采用引用传递。

Java中所有类都默认继承自Object类,而Object类中提供了一个clone()方法,这个方法的作用是返回一个Object对象的复制。这个复制函数返回的是一个新的对象而不是一个引用。

方法步骤:
1.实现clone类的首先需要继承Cloneable接口。Cloneable接口实质上是一个标识接口,没有任何方法。
2.在类中重写Object类中的clone()方法。
3.在clone方法中调用super.clone()。无论clone类的继承结构是什么,super.clone()会直接或间接调用java.lang.Object类的clone()方法。
4.把浅复制的引用指向原型对象的新克隆体。

当类中只有一些基本类型时:

class   Obj implements Cloneable{    private int aInt = 0;    public int getAInt(){        return aInt;    }    public void setAInt(){        aInt = int1;    }    public void changeInt(){        this.aInt=1;    }       public  Object clone(){        Object o = null;        try{            o = (Obj)super.clone();        }catch(CloneNotSupportedException e){            e.printStackTrace();        }        return 0;    }}       public class TestRef{        public static void main(String[] args){            Obj a = new Obj();            Obj b = (Obj)a.clone();            b.changInt();            System.out.println("a:" + a.getAInt());            System.out.println("b:" + b.getInt());        }    }

但是当类中包含了一些对象时,就需要用到深层复制了,实现方法是在对对象调用clone()方法完成复制后,接着对对象中的非基本类型的属性也调用clone()方法完成深复制。

import  java.util.Date;class Obj implements Cloneable{    private Date birth = new Date();    public Date getBirth(){        return birth;    }    public void setBirth(Date birth){        this.birth = birth;    }    public void changeDate(){        this.birth.setMonth(4);    }    public Object clone(){        Obj o = null;        try{            o = (Obj)super.clone();        }catch(CloneNotSupportedException e){            e.printStackTrace();        }        //实现深复制        o.birth = (Date)this.getBirth().clone();        return 0;    }}public class TestRef{    public static void main(String[] args){        Obj a = new Obj();        Obj b = (Obj)a.clone();        b.changeDate();        System.out.println("a="+a.getBirth());        System.out.println("b="+b.getBirth());    }}

在编程时,首先检查类有无非基本类型(即对象)的数据成员。若没有,则返回super.clone()即可;若有,确保类中包含的所有非基本类型的成员变量都实现了深复制。

Object o = super.clone();   //先执行浅复制对每一个对象arrt执行以下语句:o. attr = this.getAttr().clone();

6.什么是反射机制

    由于反射机制能够实现在运行时对类进行装载,因此能够增加程序的灵活性,但是不恰当使用反射机制,也会严重影响性能。    其实,反射机制非常重要的一个作用是可以在运行时动态地创建类的对象。    在反射机制中,class是一个非常重要的类,那么如何才能获取class类呢?

1. class.forName(“类的路径”)
2. 类名.class
3. 实例 .getClass()

class   Base{    public void f(){        System.out.println("Base");    }}class Sub extends Base{    public void f(){        System.out.printLn("Sub");    }}public class Test{    public static void main(String[] args){        try{            Class c = Class.forName("Sub");            Base b = (Base)c.newInstance();            b.f();        }catch(Exception e)            e.printStackTrace();    }}

7.Java创建对象有几种方法

1.通过new语句实例化一个对象
2.通过反射机制创建对象
3.通过clone()方法创建一个对象
4.通过反序列化的方式创建对象

8.package主要作用

1.提供多层命名空间,解决命名冲突,通过不同的package使得处于不同package中的类可以存在相同的名字。
2.对类按功能进行分类,使项目的组织更加清晰。

1 0
原创粉丝点击