如何使用ClassName作为字符串来执行“新类”?

时间:2019-09-09 18:26:30

标签: java string class arraylist

所以我正在制作一个迷你游戏,想在游戏重新启动时随机获得一个新的竞技场。 每个竞技场都是一个Java类,因为每个竞技场上的数据都会发生变化,而且在我加载和卸载地图时也是如此。

然后我进入ArrayList<String>,每次都需要做new Class。 之所以使用它的字符串,是因为我不希望类被实例化,因为加载器位于每个地图的构造函数中

我曾尝试使用class.forName()函数然后应用newInstance()似乎没有帮助。

public class Arena {

    private ArrayList<String> maps;
    private Class currentMap;

    public Arena() {
        setMaps();
        setNewMap();
    }

    private void setMaps() {
        maps = new ArrayList<String>() {
            {
                add("Beach");
                add("CandyLand");
                add("Forest");
                add("Frozen");
                add("Space");
            }
        };
    }

    private void setNewMap() {
        Random rand = new Random();
        int n = rand.nextInt(4); // count includes 0

        try {
            currentMap = (Class) Class.forName(this.maps.get(n)).newInstance();
        } catch (IllegalAccessException | ClassNotFoundException | InstantiationException e) {
            e.printStackTrace();
        }
    }

    public Class getCurrentMap() {
        return currentMap;
    }

    public ArrayList<String> getMaps() {
        return maps;
    }
}

我希望获得与new Class相同功能的结果。只需从数组中获取Class。

2 个答案:

答案 0 :(得分:2)

Class.forName(this.maps.get(n)).newInstance()很好。当然,您不应将其强制转换为Class,因为它们不是Class的实例。您的班级有一个共同的基础班吗?然后就是要上课的班级。

您不使用完全限定名称。也许你应该。

答案 1 :(得分:0)

简便方法

我怀疑您的工作太复杂了。

使用Java 13中预览的新switch语句功能,您可以轻松地做到这一点。

int i = ThreadLocalRandom.current().nextInt( 1 , 6 ); // Half-open: origin is inclusive while the bound is exclusive.
Arena arena = switch ( i )
        {
            case 1 -> new Beach();
            case 2 -> new CandyLand();
            case 3 -> new Forest();
            case 4 -> new Frozen();
            case 5 -> new Space();
            default -> null;
        };

System.out.println( "BASIL - Done." );

只需两行代码(kinda-sorta)。无需费心Class类和反思。

顺便说一句,你的声明:

  

其字符串之所以是因为我不希望该类在加载器位于每个地图的构造函数中之前就被实例化

...对我来说毫无意义。我怀疑您是在尝试避免不存在的问题。

硬路

尽管如此,您还是问过如何与Class搏斗,所以去了。

我会避免使用字符串。在这里使用字符串没有任何价值。您知道将要实例化的特定类集。因此,将其中的List,容纳List个对象的Class做成一个。我们可以随机选择这些Class对象之一来实例化该类型的对象。

定义一个包

将您的课程放在一个包中。我将使用一个名为arena的软件包。导入该软件包。

import work.basil.example.arena.* ;

定义接口Arena

创建一个接口Arena,所有五个类都将实现该接口。

package work.basil.example.arena;

public interface Arena
{
}

每个类中的实现接口

我们的五个Arena实现类中的每一个都看起来像这样。当我们看到控制台输出时,我们将知道构造函数已成功运行。

package work.basil.example.arena;

public class Beach implements Arena
{
    public Beach ( )
    {
        System.out.println( "BASIL - Constructing Beach. " );
    }
}

列出课程列表

制作一个List对象,该对象包含Class个对象,每个对象代表游戏应用中使用的类。 Java 9及更高版本中的List.of语法使此过程变得简单,产生了unmodifiable list

List < Class > classes = List.of( Beach.class , CandyLand.class , Forest.class , Frozen.class , Space.class );

从列表中随机选择一个班级

使用ThreadLocalRandom::nextInt随机选择一个。注意,如何通过使用参数化类型Arena将所选的类声明为< Arena >

int index = ThreadLocalRandom.current().nextInt(0 , classes.size()); // Half-open: origin is inclusive while the bound is exclusive.
Class < Arena > c = classes.get( index );

实例化,但Class::newInstance已弃用

实例化来自我们随机选择的类的对象。

请注意,您不赞成使用Class::newInstance的方法。 Javadoc建议使用clazz.getDeclaredConstructor().newInstance()

捕获各种可能的异常。

Arena arena = null;
try
{
    arena = c.getDeclaredConstructor().newInstance();
} catch ( InstantiationException e )
{
    e.printStackTrace();
} catch ( IllegalAccessException e )
{
    e.printStackTrace();
} catch ( InvocationTargetException e )
{
    e.printStackTrace();
} catch ( NoSuchMethodException e )
{
    e.printStackTrace();
}

结束信号。

System.out.println( "BASIL - Done." );

参见类似的code run live at IdeOne.com

  

巴西-建设森林。

     

巴西-完成。