我可能无法谷歌搜索正确的单词,但我无法找到以下问题的答案。
是否可以显式设置新类实例的超类。例如。我有一个SuperClazz
实例,想要创建Clazz
的新实例,扩展SuperClazz
。我可以做这样的事情(代码就是我想要做的,它不能编译,也不正确):
class Clazz extends SuperClazz{
Clazz(SuperClazz superInstance){
this.super = superInstance;
}
}
答案 0 :(得分:6)
你正在混合继承和授权。当一个对象调用
时super.doThis();
它不会在另一个具有对象超类类型的对象上调用doThis
。它称之为自己。 this
和super
是一回事。 super
只允许访问超类中定义的方法的版本,并在子类中重写。因此,更改超级实例没有意义:没有超级实例。
答案 1 :(得分:3)
超类总是隐式实例化,所以你不能这样做 - 在扩展类中“植入”超类。您可能想要的是复制构造函数。
答案 2 :(得分:1)
我认为您在使用的含义或术语方面存在一些误解。
实例(或对象)是您在运行时使用new Clazz()
创建的。你不能改变它(除非你使用字节码修改技巧)。
你真正想要的是创建2个类:基类及其子类。这是最简单的例子。
class SuperClazz {
}
class Clazz extends SuperClazz {
}
如果要从子类的构造函数中调用exlplitly超类构造函数,请使用super()
:
Clazz扩展SuperClazz类{
public Clazz(){
超();
}
}
答案 3 :(得分:0)
我不能声称这将始终有效,您应该始终尽可能使用复制构造函数,但在某些情况下(例如您无权更改代码或不想产生复杂性),您可以使用它(例如:),
import java.lang.reflect.Field;
import java.net.Socket;
public class SmarterSocket extends Socket {
public SmarterSocket(Socket s) {
super(); // default constructor for super instance
// will iterate over public/private fields of "s" (superclass not included)
for(Field f : s.getClass().getDeclaredFields()){
try {
f.setAccessible(true);
f.set(this,f.get(s));
}catch (Exception ignored){}
}
}
public void doSmartStuff(){
System.out.println("smarter");
}
}
...
public static void main(String[] args){
try {
Socket s = new Socket();
s.connect(new InetSocketAddress("stackoverflow.com",80));
SmarterSocket ss = new SmarterSocket(s);
ss.close();
System.out.println("is SmartSocket closed: " + ss.isClosed());
System.out.println("is Socket closed: " + s.isClosed());
s.getOutputStream().write("hellow".getBytes()); // write to s
} catch (IOException e) {
e.printStackTrace();
}
}
is SmartSocket closed: true
is Socket closed: false
java.io.IOException: Socket Closed
at java.base/java.net.AbstractPlainSocketImpl.getOutputStream(AbstractPlainSocketImpl.java:489)
at java.base/java.net.Socket$3.run(Socket.java:972)
at java.base/java.net.Socket$3.run(Socket.java:970)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.net.Socket.getOutputStream(Socket.java:969)
at Main.main(Main.java:47)
我使用上面的例子在套接字内挂钩一些监视器
但你必须谨慎:
1- 反射很复杂:有时字段被用于同步或更复杂的东西,你可能不应该更新静态(或更明确地说是静态最终)字段,你应该对你代理的类的内部有适当的了解它,并进行一些繁重的测试以确保一切顺利
2- 反射在运行时很慢:测试它,如果它适合你就让它在那里