- 0x01 前言
- 0x02 获得类实例的方法
- 0x02.1 例子-类(用于理解的)
- 0x02.2 类的.class语法
- 0x02.3 对象的getClass()方法
- 0x02.4 通过-类加载器
- 0x02.5 Class的静态方法 forName(String classPath)
- 0x02.5.1 实例化-例子
- 0x02.5.2 额外知识一
- 0x02.5.2.1 String[].class-JNI字段描述符
- 0x02.5.2.2 Object[].class-JNI字段描述符
- 0x02.5.2.3 Integer[].class-JNI字段描述符
- 0x02.5.2.4 Boolean[].class-JNI字段描述符
- 0x02.5.2.5 byte[].class-JNI字段描述符
- 0x02.5.2.6 char[].class-JNI字段描述符
- 0x02.5.2.7 short[].class-JNI字段描述符
- 0x02.5.2.8 int[].class-JNI字段描述符
- 0x02.5.2.9 long[].class-JNI字段描述符
- 0x02.5.2.10 float[].class-JNI字段描述符
- 0x02.5.2.11 double[].class-JNI字段描述符
- 0x02.5.3 额外知识二
0x01 前言
了解到如何获取一个类的Class对象是我们入门反射的第一步。
因为在Java中反射操作的是java.lang.Class对象。
因此我们需要学会的第一步就是如何获取到Class对象, 为后面打好基础。
0x02 获得类实例的方法
0x02.1 例子-类(用于理解的)
// 例如现在有一个 Foo类
// 请实例化它并调用 print() 方法
// 额外提问: 它没有构造方法,能不能被反射new呢?
// 答案是可以的,在本文0x02.5.1中可以看得到结果
package 反射;
class Foo {
void print() {
System.out.println("foo的print方法冲冲冲");
}
}
0x02.2 类的.class语法
package 反射;
public class Test {
public static void main(String[] args) {
Class fooClass1 = Foo.class;
try {
Foo foo = (Foo) fooClass1.newInstance();
foo.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
# 运行结果
foo的print方法冲冲冲
进程已结束,退出代码 0
0x02.3 对象的getClass()方法
package 反射;
public class Test {
public static void main(String[] args) {
Foo f = new Foo();
Class fooClass2 = f.getClass();
try {
Foo foo = (Foo) fooClass2.newInstance();
foo.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
# 运行结果
foo的print方法冲冲冲
进程已结束,退出代码 0
0x02.4 通过-类加载器
package 反射;
public class Test {
public static void main(String[] args) {
Class fooClass3 = null;
try {
fooClass3 = ClassLoader.getSystemClassLoader().loadClass("反射.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
Foo foo = (Foo) fooClass3.newInstance();
foo.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
# 运行结果
foo的print方法冲冲冲
进程已结束,退出代码 0
0x02.5 Class的静态方法 forName(String classPath)
0x02.5.1 实例化-例子
package 反射;
public class Test {
public static void main(String[] args) {
Class fooClass4 = null;
try {
fooClass4 = Class.forName("反射.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
// 注意: 如果反射的这个类,没有构造方法,那么也是可以被new出来的
// 因为Java的类没有构造方法的时候,也会为类添加一个默认的空构造方法
// 记得这一点,代码审计时遇到可控Class.forName但是不可控newInstance()的情况
// 那么就可以去找那种没有设置构造方法的工具类,进行实例化
Foo foo = (Foo) fooClass4.newInstance();
foo.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
# 运行结果
foo的print方法冲冲冲
进程已结束,退出代码 0
0x02.5.2 额外知识一
如果说获取的Class对象为数组类型的话,需要特殊注意。
这种情况需要使用 Java JNI字段描述符
注意事项:
一个数组 [Ljava.lang.String;
二维数组 [[Ljava.lang.String;
三维数组 [[[Ljava.lang.String;
0x02.5.2.1 String[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> stringArray = Class.forName("[Ljava.lang.String;");
Class<String[]> test = String[].class;
System.out.println(stringArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.2 Object[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> objectArray = Class.forName("[Ljava.lang.Object;");
Class<Object[]> test = Object[].class;
System.out.println(objectArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.3 Integer[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> integerArray = Class.forName("[Ljava.lang.Integer;");
Class<Integer[]> test = Integer[].class;
System.out.println(integerArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.4 Boolean[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> booleanArray = Class.forName("[Ljava.lang.Boolean;");
Class<Boolean[]> test = Boolean[].class;
System.out.println(booleanArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.5 byte[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> byteArray = Class.forName("[B");
Class<byte[]> test = byte[].class;
System.out.println(byteArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.6 char[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> charArray = Class.forName("[C");
Class<char[]> test = char[].class;
System.out.println(charArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.7 short[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> shortArray = Class.forName("[S");
Class<short[]> test = short[].class;
System.out.println(shortArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.8 int[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> intArray = Class.forName("[I");
Class<int[]> test = int[].class;
System.out.println(intArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.9 long[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> longArray = Class.forName("[J");
Class<long[]> test = long[].class;
System.out.println(longArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.10 float[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> floatArray = Class.forName("[F");
Class<float[]> test = float[].class;
System.out.println(floatArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.2.11 double[].class-JNI字段描述符
public class JNITest {
public static void main(String[] args) {
try {
Class<?> doubleArray = Class.forName("[D");
Class<double[]> test = double[].class;
System.out.println(doubleArray == test);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
0x02.5.3 额外知识二
# 在使用 Class.forName() 调用内部类的时候需要使用 $符号 来代替 .(点号)
# 例如现在有一个 com.alibaba.Test里面有一个内部类叫Hello
# 然后现在想调用 om.alibaba.Test 里面的 Hello类
# 那么调用的时候就应该这么写 com.alibaba.Test$Hello
# 换成代码就是
public class Test {
public static void main(String[] args) {
Class tClass = null;
try {
tClass = Class.forName("com.alibaba.Test$Hello");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}