有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

类是在Java中实例化大量子类的最有效方法?

我正在从事一个项目,该项目需要使用大量扩展特定抽象类的类对象。手动实例化需要调用每个对象的单个构造函数,这开始污染我的客户机类

该项目的原始代码太长,无法在此网站上发布,因此我有一个简化的示例:

假设有一个名为Letter的抽象类:

public abstract class Letter{
    String letter;
}

以及26个扩展信函摘要类的单个信函类:

public class A extends Letter{
    this.letter = "A";
}

public class B extends Letter{
    this.letter = "B";
}
... and so on

这就是我寻求帮助的地方-有一个名为Alphabet的客户端类:

public class Alphabet{
    public List<Letter> getLetters(){
        List<Letter> letters = new ArrayList<>();
        A a = new A();
        B b = new B();
        C c = new C();
        list.add(a);
        list.add(b);
        list.add(c);
        ...the list goes on

        return letters;
    }
}

如您所见,手动实例化每个字母并不理想。我正在寻找一种在运行时动态创建类对象列表的方法

也许与此类似:

public class Alphabet{
    public List<Letter> getLetters(){
        List<Letter> letters = getAllClassesExtending(Letter.class);
        return letters;
        //list would then contain A,B,C,D,E,F,G, etc.
    }
}

我最终希望能够创建一个新类,并将其自动添加到客户端类中的对象列表中,而无需修改客户端类(例如,我不希望显式引用客户端类中的每个字母类)


共 (2) 个答案

  1. # 1 楼答案

    这听起来像是enum的典型用例。一个enum的常量可以有一个带有代码的类主体,重写基类型的方法,甚至可以声明新字段

    获取所有子类型的实例的任务意味着一组封闭的子类型,它与enum类型的行为相匹配

    public enum Letter {
        A {
            @Override
            public boolean isVowel() {
                return true;
            }
        },
        B, C, D,
        E {
            @Override
            public boolean isVowel() {
                return true;
            }
        },
        F, G, H,
        I {
            @Override
            public boolean isVowel() {
                return true;
            }
        }, J, K, L, M, N,
        O {
            @Override
            public boolean isVowel() {
                return true;
            }
        }, P, Q, R, S, T,
        U {
            @Override
            public boolean isVowel() {
                return true;
            }
        }, V, W, X, Y, Z;
        ;
        String letter = name();
    
        public static List<Letter> getLetters() {
            return Arrays.asList(values());
        }
    
        public boolean isVowel() {
            return false;
        }
    }
    

    这表明重写方法是可能的,而且获取所有实例(作为数组)的方法也是免费的。此外,名称在本质上是指定的,没有冗余

    如果您想拥有一组开放的子类,以便在编译代码后进行潜在的扩展,那么应该查看Service Provider concept^{}类。该机制不会自动查找子类,而只查找那些在META-INF中的文件中或通过模块声明声明声明为服务提供者的子类,另一方面,它为您提供了一个健壮的、已建立的解决方案,该解决方案将由Java开发人员维护,甚至与平台一起发展,喜欢融入新的模块概念

  2. # 2 楼答案

    您可以使用Reflections库在运行时查找类,例如,如果所有类都位于com.letters包下并且没有参数构造函数:

    public List<? extends Letter> getLetters(){
      Reflections reflections = new Reflections("com.letters");
      Set<Class<? extends Letter>> classes = reflections.getSubTypesOf(Letter.class);
      return classes.stream()
            .map(clazz -> {
                try {
                    return clazz.newInstance();
                } catch (InstantiationException | IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                }
            })
            .collect(Collectors.toList());
    }
    

    这不是查找类的最有效方法,如果此代码位于关键路径上,则可能需要缓存结果