Class<?> c = Class.forName("package1.A");
//full package name --------^^^^^^^^^^
//or simpler without Class.forName:
//Class<package1.A> c = package1.A.class;
//In our case we need to use
Constructor<?> constructor = c.getDeclaredConstructor();
//note: getConstructor() can return only public constructors
//so we needed to search for any Declared constructor
//now we need to make this constructor accessible
constructor.setAccessible(true);//ABRACADABRA!
Object o = constructor.newInstance();
package package1;
public class Outer {
class Inner{
Inner(){
System.out.println("non-public constructor of inner class");
}
}
}
Package 2
package package2;
import package1.Outer;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
Outer outerObject = new Outer();
Class<?> innerClazz = Class.forName("package1.Outer$Inner");
// constructor of inner class as first argument need instance of
// Outer class, so we need to select such constructor
Constructor<?> constructor = innerClazz.getDeclaredConstructor(Outer.class);
//we need to make constructor accessible
constructor.setAccessible(true);
//and pass instance of Outer class as first argument
Object o = constructor.newInstance(outerObject);
System.out.println("we created object of class: "+o.getClass().getName());
}
}
/**
* To fix issues with wrong edge-to-edge bottom sheet top padding and status bar icon color…
* …we need to call [BottomSheetDialog.EdgeToEdgeCallback.setPaddingForPosition] which is a private function from a private class.
* See: https://github.com/material-components/material-components-android/issues/2165
*/
fun adjustBottomSheet(aDialog : BottomSheetDialog) {
// Get our private class
val classEdgeToEdgeCallback = Class.forName("com.google.android.material.bottomsheet.BottomSheetDialog\$EdgeToEdgeCallback")
// Get our private method
val methodSetPaddingForPosition: Method = classEdgeToEdgeCallback.getDeclaredMethod("setPaddingForPosition", View::class.java)
methodSetPaddingForPosition.isAccessible = true
// Get private field containing our EdgeToEdgeCallback instance
val fieldEdgeToEdgeCallback = BottomSheetDialog::class.java.getDeclaredField("edgeToEdgeCallback")
fieldEdgeToEdgeCallback.isAccessible = true
// Get our bottom sheet view field
val fieldBottomField = BottomSheetDialog::class.java.getDeclaredField("bottomSheet")
fieldBottomField.isAccessible = true
// Eventually call setPaddingForPosition from EdgeToEdgeCallback instance passing bottom sheet view as parameter
methodSetPaddingForPosition.invoke(fieldEdgeToEdgeCallback.get(aDialog),fieldBottomField.get(aDialog))
}
另外,您可能需要确保proguard不会丢弃您试图访问的方法:
# Needed for now to fix our bottom sheet issue from
com.google.android.material:material:1.4.0-alpha02
-keep class com.google.android.material.bottomsheet.BottomSheetDialog$EdgeToEdgeCallback {
private void setPaddingForPosition(android.view.View);
}
5条答案
按热度按时间9ceoxa921#
nested class-在其他类中定义的类(包括静态类和非静态类)
内部类-非静态嵌套类(内部类的示例只能通过外部类的示例创建)
非嵌套(顶层)类
根据您的问题,我们知道您要访问的构造函数不是公共的。所以你的类可能看起来像这样(
A
类在与我们不同的包中)要创建这个类的示例,我们需要找到我们想要调用的构造函数,并使其可访问。完成后,我们可以使用
Constructor#newInstance(arguments)
创建示例。嵌套类和内部类
如果你想用
Class.forName
访问嵌套的(静态和非静态)类,你需要使用语法:Outer$Nested
表示Nested
类在Outer
类中声明。嵌套类与方法非常相似,它们可以访问其外部类的所有成员(包括私有成员)。但是我们需要记住,内部类的示例要存在,需要它的外部类的示例。通常我们通过以下方式创建它们:
因此,您可以看到Inner类每个示例都有一些关于其外部类的信息(对外部示例的引用存储在
this$0
字段中,更多信息:在调试Java时,如果一个变量在IntelliJ IDEA中的名称为“this$0”,这意味着什么?)因此,在使用
Constructor#newInstance()
创建Inner
类的示例时,您需要将Outer
类的示例作为第一个参数传递(以模拟outer.new Inner()
行为)。这里有一个例子。
Package 1
Package 2
静态嵌套类
静态嵌套类的示例不需要外部类的示例(因为它们是静态的)。所以在这种情况下,我们不需要寻找以
Outer.class
作为第一个参数的构造函数。我们不需要将外部类的示例作为第一个参数传递。换句话说,代码将与非嵌套(顶级)类相同(可能除了当引用Class.forName()
中的嵌套类(如Class.forName("some.package.Outer$Nested1$NestedNested")
)时,需要在类名中添加use$
而不是.
)。pepwfjgg2#
Class.forName
应该可以工作。如果类位于"package.access"
安全属性中的包层次结构列表中,则需要使用适当的权限(通常是所有权限;或者没有安全管理器)。如果你正在尝试使用
Class.newInstance
,不要。Class.newInstance
处理异常很差。相反,获取一个Constructor
并在其上调用newInstance
。如果没有异常跟踪,很难看出您遇到了什么问题。和以往一样,大多数但不是所有的反射用法都是坏主意。
ecfdbz9o3#
我们最近发布了一个库,它可以帮助我们通过反射访问私有字段、方法和内部类:BoundBox
对于像
它提供了如下语法:
要创建BoundBox类,您唯一需要做的就是编写
@BoundBox(boundClass=Outer.class)
,BoundBoxOfOuter
类将立即生成。idfiyjo84#
我有要求复制对象的旧版本的字段的值,如果该值在最新版本中为空。我们有这两个选择。
核心Java:
使用Spring [org.springframework.beans.BeanWrapper]:
dy2hfwbg5#
不得不在Android上做一些类似的事情,这是我想到的:
另外,您可能需要确保proguard不会丢弃您试图访问的方法: