Java中级——组合和继承

组合和继承

这是两种不同的实现方式,不能混用

java 复制代码
public class GetterErrorDemo {

    private static final String TAG = GetterErrorDemo.class.getSimpleName();

    public static class Node {
        private final String name;

        public Node(String name) {
            this.name = name;
        }

        @NonNull
        @Override
        public String toString() {
            return "Node{" + name + '}';
        }
    }

    public static class BaseInfo {
        private Node mNode;

        public Node getNode() {
            return mNode;
        }

        public void setNode(Node node) {
            this.mNode = node;
        }

        @NonNull
        @Override
        public String toString() {
            // 关键点:打印的是字段 mNode,而不是 getNode()
            return "BaseViewInfo{node=" + mNode + '}';
        }
    }

    public static class ChildInfo extends BaseInfo {
        private final BaseInfo origin;
        private String mLabel; // child 自己的属性

        public ChildInfo(BaseInfo origin) {
            this.origin = origin;
        }

        @Override
        public Node getNode() {
            return origin.getNode(); // getter 重写,委托给原始控件
        }

        public void setLabel(String label) {
            this.mLabel = label;
        }

        @NonNull
        @Override
        public String toString() {
            // 父类字段 mNode 从没被赋值 → 打印出 null,但 getNode() 却非空
            return "ChildInfo{" + super.toString() + ", label=" + mLabel + '}';
        }
    }

    public static void demo() {
        BaseInfo origin = new BaseInfo();
        origin.setNode(new Node("node1"));
        ChildInfo child = new ChildInfo(origin);
        child.setLabel("我是child自己的属性");

        ArrayList<BaseInfo> list = new ArrayList<>();
        list.add(origin);
        list.add(child);
        for (BaseInfo baseInfo : list) {
            Log.d(TAG, "info = " + baseInfo);
        }
        origin.setNode(new Node("node2"));
        Log.d(TAG, "--- after origin.setNode(node2) ---");
        for (BaseInfo baseInfo : list) {
            Log.d(TAG, "info = " + baseInfo);
        }

        Log.d(TAG, "origin.getNode().equals(child.getNode()) = " + origin.getNode().equals(child.getNode()));
    }
}

对于如上代码,ChildInfo即继承了BaseInfo,又组合了BaseInfo,导致toString打印的mNode始终为空,而重写的getNode()又不为空,导致增加排查难度

复制代码
info = BaseInfo{node=Node{node1}}
info = ChildInfo{BaseInfo{node=null}, label=我是child自己的属性}
--- after origin.setNode(node2) ---
info = BaseInfo{node=Node{node2}}
info = ChildInfo{BaseInfo{node=null}, label=我是child自己的属性}
origin.getNode().equals(child.getNode()) = true

继承(不共有域)

java 复制代码
public class GetterCopyDemo {

    private static final String TAG = GetterCopyDemo.class.getSimpleName();

    public static class Node {
        private final String name;

        public Node(String name) {
            this.name = name;
        }

        @NonNull
        @Override
        public String toString() {
            return "Node{" + name + '}';
        }
    }

    public static class BaseInfo {
        private Node mNode;

        public BaseInfo() {
        }

        // 拷贝构造:以后新增字段只改这里一处
        public BaseInfo(BaseInfo other) {
            this.mNode = other.mNode;
        }

        public Node getNode() {
            return mNode;
        }

        public void setNode(Node node) {
            this.mNode = node;
        }

        @NonNull
        @Override
        public String toString() {
            return "BaseInfo{node=" + mNode + '}';
        }
    }

    public static class ChildInfo extends BaseInfo {
        private String mLabel; // child 自己的属性

        public ChildInfo(BaseInfo origin) {
            super(origin); // 一行复制 origin 的所有字段
        }

        public void setLabel(String label) {
            this.mLabel = label;
        }

        @NonNull
        @Override
        public String toString() {
            return "ChildInfo{" + super.toString() + ", label=" + mLabel + '}';
        }
    }

    public static void demo() {
        Log.d(TAG, "------------------------------------------------");
        BaseInfo origin = new BaseInfo();
        origin.setNode(new Node("node1"));

        ChildInfo child = new ChildInfo(origin);
        child.setLabel("我是child自己的属性");

        ArrayList<BaseInfo> list = new ArrayList<>();
        list.add(origin);
        list.add(child);
        for (BaseInfo baseInfo : list) {
            Log.d(TAG, "info = " + baseInfo);
        }

        // child 是独立副本:改 origin 不会影响 child
        origin.setNode(new Node("node2"));
        Log.d(TAG, "--- after origin.setNode(node2) ---");
        for (BaseInfo baseInfo : list) {
            Log.d(TAG, "info = " + baseInfo);
        }
    }
}

对于如上代码,ChildInfo构造函数调用BaseInfo的拷贝构造,同时toString打印父类字段和子类字段,避免了上面的打印和实际值不一样的问题

复制代码
info = BaseInfo{node=Node{node1}}
info = ChildInfo{BaseInfo{node=Node{node1}}, label=我是child自己的属性}
--- after origin.setNode(node2) ---
info = BaseInfo{node=Node{node2}}
info = ChildInfo{BaseInfo{node=Node{node1}}, label=我是child自己的属性}
origin.getNode().equals(child.getNode()) = false

组合(共有域)

复制代码
public class GetterDelegateDemo {

    private static final String TAG = GetterDelegateDemo.class.getSimpleName();

    public static class Node {
        private final String name;

        public Node(String name) {
            this.name = name;
        }

        @NonNull
        @Override
        public String toString() {
            return "Node{" + name + '}';
        }
    }

    public interface ViewInfo {
        Node getNode();
    }

    public static class BaseInfo implements ViewInfo {
        private Node mNode;

        @Override
        public Node getNode() {
            return mNode;
        }

        public void setNode(Node node) {
            this.mNode = node;
        }

        @NonNull
        @Override
        public String toString() {
            return "BaseInfo{node=" + mNode + '}';
        }
    }

    public static class ChildInfo implements ViewInfo {
        private final ViewInfo origin; // 父类那部分委托 origin,自己不存
        private String mLabel;         // child 自己新增的属性,自己存

        public ChildInfo(ViewInfo origin) {
            this.origin = origin;
        }

        @Override
        public Node getNode() {
            return origin.getNode(); // 委托 origin
        }

        public String getLabel() {
            return mLabel; // 自己的属性走自己的字段
        }

        public void setLabel(String label) {
            this.mLabel = label;
        }

        @NonNull
        @Override
        public String toString() {
            return "ChildInfo{origin=" + origin + ", label=" + mLabel + '}';
        }
    }

    public static void demo() {
        Log.d(TAG, "------------------------------------------------");
        BaseInfo origin = new BaseInfo();
        origin.setNode(new Node("node1"));

        ChildInfo child = new ChildInfo(origin);
        child.setLabel("我是child自己的属性");

        ArrayList<ViewInfo> list = new ArrayList<>();
        list.add(origin);
        list.add(child);
        for (ViewInfo baseInfo : list) {
            Log.d(TAG, "info = " + baseInfo);
        }

        // child 是委托:改 origin 会影响 child
        origin.setNode(new Node("node2"));
        Log.d(TAG, "--- after origin.setNode(node2) ---");
        for (ViewInfo baseInfo : list) {
            Log.d(TAG, "info = " + baseInfo);
        }
        Log.d(TAG, "origin.getNode().equals(child.getNode()) = " + origin.getNode().equals(child.getNode()));
    }
}

对于如上代码,ChildInfo持有BaseInfo,将父类字段给BaseInfo,并抽象ViewInfo用于遍历,同时toString打印父类字段和子类字段,避免了上面的打印和实际值不一样的问题

复制代码
info = BaseInfo{node=Node{node1}}
info = ChildInfo{origin=BaseInfo{node=Node{node1}}, label=我是child自己的属性}
--- after origin.setNode(node2) ---
info = BaseInfo{node=Node{node2}}
info = ChildInfo{origin=BaseInfo{node=Node{node2}}, label=我是child自己的属性}
origin.getNode().equals(child.getNode()) = true
相关推荐
用户3721574261357 分钟前
Java 拆分 Word 文档教程:按页、分页符和分节符拆分
java
qq_3449205611 分钟前
Qt事件过滤器
开发语言·c++·qt
liyinchi198817 分钟前
微信小程序支付遇到“由于小程序违规,支付功能暂时无法使用” 解决办法
java·微信小程序·go
执明wa28 分钟前
Android RecyclerView 多类型, 多种 Item
android·xml·开发语言·设计模式·android studio
横木沉32 分钟前
IntelliJ IDEA 无法识别 Git:Git is not installed 问题解决
java·git·github·intellij-idea
程序员yu39 分钟前
数智码力:Python作用域完全梳理,全局变量局部变量不再混乱
开发语言·python·学习
code2cat43 分钟前
Java进阶篇之Optional
java
用户8181870627461 小时前
第29章 死信队列与延迟消息实战
java·后端