【问题标题】:Java set super instance of instanceJava设置实例的超级实例
【发布时间】:2012-01-29 20:26:25
【问题描述】:

我可能只是无法用谷歌搜索正确的词,但我找不到以下问题的答案。

是否可以显式设置新类实例的超类。例如。我有一个SuperClazz 实例并想创建一个扩展SuperClazzClazz 的新实例。我可以做这样的事情吗(代码正是我想做的,它不编译也不正确):

    class Clazz extends SuperClazz{

Clazz(SuperClazz superInstance){
    this.super = superInstance;
}
}

【问题讨论】:

  • this.super 不是一个类,而是一个实例。并且没有 superinstance 这样的东西,因为 super 是实例本身。
  • 也许您可以重新表述您的问题,并询问您所面临的“现实世界”问题,您希望使用这种结构来解决。

标签: java class inheritance super superclass


【解决方案1】:

您正在混合继承和委托。当一个对象调用

super.doThis();

它不会在另一个具有对象超类类型的对象上调用doThis。它在他自己身上调用它。 thissuper 是一回事。 super 只允许访问在超类中定义并在子类中覆盖的方法的版本。因此,更改超级实例没有任何意义:没有超级实例。

【讨论】:

    【解决方案2】:

    超类总是被隐式实例化,所以你不能这样做——在扩展类中“植入”超类。您可能想要的是一个复制构造函数。

    【讨论】:

    • 是的,我想要一种方法来避免使用复制构造器。
    【解决方案3】:

    我认为您对所使用的含义或术语有一些误解。

    实例(或对象)是您在运行时使用new Clazz() 创建的。您无法更改它(除非您使用字节码修改技巧)。 您真正想要的是创建 2 个类:基类及其子类。这是最简单的例子。

    class SuperClazz {
    }
    
    class Clazz extends SuperClazz {
    }
    

    如果你想从子类的构造函数中调用超类的构造函数,请使用super(): 类 Clazz 扩展 SuperClazz { 公共克拉兹(){ 极好的(); } }

    【讨论】:

    • 不,我认为我使用了正确的术语。问题是 java 似乎没有超级实例的概念。我最近在使用 JS,您可以在其中弄乱原型实例,因此我虽然 java 可能会将超类的实例与子类的实例分开,但事实并非如此? (是的,我知道 JS 和 Java 是两个不同的东西,我只是虽然这个特定方面有一些来自 java 的起源......)
    【解决方案4】:

    我不能声称这将始终有效,您应该始终尽可能使用复制构造函数,但在某些情况下(例如您无权更改代码或不想产生复杂性)您可以使用它(例如:),

    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- 反射在运行时很慢:测试它,如果它适合你就让它在那里

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 2015-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多