# Java 基础
Java面试题# 实例化对象有哪些方式?
参考答案
- ① 最常用的直接
new()
的方式创建;
A a = new A();
- ② 用
clone
方法创建, 需要类实现Cloneable
接口;
A a = (A)B.clone();
- ③ 用
Class.forName
方法获取类,在调用类的newinstance()
反射机制创建;
Class<?> cls = Class.forName("com.cn.A");
A a = (A)cls.newInstance();
- ④ 用
Objenesis
,Objenesis是一个Java的库,主要用来创建特定的对象。即便没有空的构造函数也可以创建对象。
Objenesis objenesis = new ObjenesisStd();
A a = objenesis.newInstance(A.class);
- ⑤ 使用
SpringObjenesis
,这是Spring对Objenesis
接口的一个实现。由Spring4.2之后提供的(ObjenesisCglibAopProxy在 Spring4.0就有了)
Objenesis objenesis = new SpringObjenesis();
A a = objenesis.newInstance(A.class);
扩展阅读
Objenesis主要应用场景:
- 序列化,远程调用和持久化 -对象需要实例化并存储为到一个特殊的状态,而没有调用代码
- 代理,AOP库和Mock对象 -类可以被子类继承而子类不用担心父类的构造器。
- 容器框架 -对象可以以非标准的方式被动态实例化(比如Spring就是容器框架)
# instanceof、isInstance、isAssignableFrom区别
参考答案
instanceof
运算符 只被用于对象引用变量,检查左边的被测试对象 是不是 右边类或接口的 实例化。如果被测对象是null值,则测试结果总是false。- 伪代码:自身实例或子类实例 instanceof 自身类 返回true
- 例:String s=new String("javaisland");
- 例:System.out.println(s instanceof String); //true
Class类的
isInstance(Object obj)
方法,obj
是被测试的对象,如果obj
是调用这个方法的class或接口 的实例,则返回true。这个方法是instanceof运算符的动态等价。- 伪代码:自身类.class.isInstance(自身实例或子类实例) 返回true
- 例:String s=new String("javaisland");
- 例:System.out.println(String.class.isInstance(s)); //true
Class类的
isAssignableFrom(Class cls)
方法,如果调用这个方法的class或接口 与 参数cls表示的类或接口相同,或者是参数cls表示的类或接口的父类,则返回true。- 伪代码:自身类.class.isAssignableFrom(自身类或子类.class) 返回 true
- 例:System.out.println(ArrayList.class.isAssignableFrom(Object.class)); //false
- 例:System.out.println(Object.class.isAssignableFrom(ArrayList.class)); //true
# new String() 和 toString() 的区别
参考答案
toString()
是调用了Object 对象类的toString()
方法,默认返回当前对象(c)的内存地址即hashCode
。也就是[class name]@[hashCode]
格式,如:[B@312b1dae
。- new String(para)是根据para是一个字节数组,使用Java虚拟机默认的编码格式,将这个字节数组decode为对应的字符,返回的是真实的值。
该问题发生在使用Socket读取客户端的字节流,把bytes.toString()
却输出了hashCode
值,而用new String(bytes)
则正确的打出了值。
# 如何理解Java关键字this
参考答案
- 首先,this关键字必须放在非静态方法里面。
- 可以使用this关键字引用成员变量。
- 使用this关键字在自身构造方法内部引用其它构造方法。
- 使用this关键字代表自身类的对象。
- 使用this关键字引用成员方法。
this关键字是一个对象的默认引用。作为对象的默认引用,有两种情形:
- 在
构造器
中,引用该构造器执行初始化的
对象。 - 在
方法
中,引用调用该方法的
对象。
# 构造方法的作用
参考答案
- 首先每个类都有一个无参数的默认构造函数。这也是为什么有些类即便没有写构造方法也可以通过new来实例化。
- 为了初始化成员属性,而不是初始化对象,初始化对象是通过new关键字实现的。
- 通过new调用构造方法初始化对象,编译时根据参数签名来检查构造函数。
- 创建子类对象会调用父类构造方法但不会创建父类对象,只是调用父类构造方法初始化父类成员属性;
扩展阅读
构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。
class a
{
a _a = new a();
public a()
{
_a = new a();
a _b = new a();
}
}
以上三种情况都会造成栈溢出,会造成一个无穷递归的调用栈。
注意事项
继承中的构造方法,有下面这些规则需要遵守
- 1.子类的构造过程中必须调用其父类的构造方法
- 2.子类可以在自己的构造方法中使用super(参数列表)调用父类的构造方法
- (1).可以使用this(参数列表)调用自己这个类的其他的构造方法 调用this的时候也调用了父类的构造方法
- (2).如果调用了super,必须写在子类构造方法的第一行
- (3).this也必须放在第一行,所以this,super在一个构造方法里无法同时出现 实际上严格来讲,还是能实现的,用内部类。在内部类里面,可以使用一个this或者super
- 3.如果子类的构造方法中没有显示地调用父类构造方法,系统默认调用父类那个无参数的构造方法
- 4.如果子类构造方法中既没有显示调用父类构造方法,而父类中又没有无参的构造方法,编译会报错。 构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。