Java是如何在运行时识别对象和类的信息的?
一般讲是两种:
1. “传统的”RTTI,他假定我们在编译时已经知道所有的类型。
2. 反射,并允许在运行时发现和使用类的信息。
反射可以拿到任何类的信息,包括内部类和匿名类,可以调用任意方法,访问和修改域(final类不能修改)。对于private等修饰词,只需要setAccessible(true)一下即可,很牛逼的呢。
RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
package nihaokid;
import java.util.Arrays;
import java.util.List;
abstract class shape
{
void draw(){System.out.println(this+".draw()");}
abstract public String toString();
}
class circle extends shape
{
@Override
public String toString() {
return "circle";
}
}
class sqare extends shape
{
@Override
public String toString() {
return "sqare";
}
}
public class testRTTI
{
public static void main(String[] asd)
{
List<shape> shapelist = Arrays.asList(new circle(),new sqare());
for(shape a:shapelist)
a.draw();
}
}
输出:其实就是多态而已
circle.draw()
sqare.draw()
为使用类而做的准备 写道
1. 加载。获取到字节码,创建class对象
2. 链接。验证类中的字节码,为静态域分配存储空间,解析其他类引用。
3. 初始化。初始化超类,静态语句执行。(静态中,先初始化块,再初始化变量。)
泛型杂记 写道
Class<? extends Number> integer = int.class;//可以 <? extends A & B>
Class<Objact> ss = String.class;//编译错误
class A{};
class B extends A{};
Class<A> hello = B.class.getSuperclass();//编译时错误
Class<? super B> hello = B.class.getSuperclass();//可以
泛型的擦除问题:核心动机--使得泛化的客户端可以用非泛化的类库来使用。“迁移兼容性”
泛型对传入的值进行编译期检查,对传出的值进行值的转换。
任何在运行时需要知道确切类型信息的操作都将无法知道
class Erased<T>{
private final static int Size = 100;
private static void f(Object arg){
if(arg instanceof T){}//Error
T var = new T();//Error
T[] array1 = new T[Size];//Error
T[] array2 = (T)new Object[Size];//Unchecked warning
}
}
class AA{};
class BB extends AA{};
List<? extends AA> list = new ArrayList<BB>();
list.add(new BB());//编译错误
list.add(new AA());//编译错误
list.add(new Object());//编译错误
内部类杂记 写道
1、隐藏你不想让别人知道的操作,也即封装性。
2、一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!
内部类的功能在于,每个内部类都能独立的继承一个接口的实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多重继承的解决方案变得完整,并且内部类允许继承多个非接口类型(类或抽象类)。通过内部类分别继承一个基类,外部类创建内部类的对象,并使用内部类的方法,变相地实现了多继承。
java内部类有什么好处?为什么需要内部类?
1、举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。
2、真正的原因是这样的,java中的内部类和接口加在一起,可以解决常被C++程序员抱怨java中存在的一个问题:没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。
静态内部类和非静态内部类的区别
1、和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。
2、在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。
类型杂记 写道
Class类中的isInstance()方法可以更灵活的代替instanceof表达式。
Class.forName()和clazz.class的区别
同样是拿到class类型,但前者会初始化该类,而后者不会,即在执行静态初始化器和静态初始化块。
前者在运行时获取,需要加异常,后者编译时检查,显然前者灵活,后者安全。