简体   繁体   English

将对象转换为 T 类型的类

[英]Casting an Object into a Class of type T

Let's say I have an empty class called ClsA() , and a subclass of it called ClsB() like so:假设我有一个名为ClsA()的空类,它的子类称为ClsB()如下所示:

public static class ClsA {}

public static class ClsB extends ClsA {}

Supposing that we now have an ArrayList of ClsA type objects, I want to be able to count how many elements in the ArrayList are actually of type ClsA or ClsB.假设我们现在有一个 ClsA 类型对象的 ArrayList,我希望能够计算 ArrayList 中有多少元素实际上是 ClsA 或 ClsB 类型。 Based on some searching, I found out that the following function works wonders:根据一些搜索,我发现以下功能可以创造奇迹:

   public static <T> int countInstances(ArrayList<?> list, Class<T> cls) {
        int count = 0;
        for(Object o : list) {
            if(cls.isInstance(o)) {
                count++;
            }
        }
        return count;
    }

Indeed, the following sample main method does give the correct output.实际上,以下示例 main 方法确实提供了正确的输出。

public static void main(String[] args) {
    // write your code here
    ArrayList<ClsA> test = new ArrayList<>();
    test.add(new ClsA());
    test.add(new ClsB());
    test.add(new ClsA());
    test.add(new ClsB());
    int result = countInstances(test,ClsB.class);
    System.out.println(result);
}

However, let's say that ClsB is now defined as followed:但是,假设 ClsB 现在定义如下:

public static class ClsB extends ClsA {
    private final String type;
    public ClsB(String type) {
        this.type = type;
    }

    public String getType() {return type;}
}

I now want to count how many ClsB instances of a specific type are present in the given ArrayList.我现在想计算给定 ArrayList 中存在多少特定类型的 ClsB 实例。 After checking in my countInstances() that an element is of the given class (in this example ClsB), I want to be able to also check if the type given to the method matches the type of the element.在我的countInstances()中检查元素属于给定类(在此示例中为 ClsB)后,我还希望能够检查提供给方法的类型是否与元素的类型匹配。 Is there any way to actually cast Object o into an instance of the given class since the compiler doesn't really know its actual type?有没有办法将Object o实际转换为给定类的实例,因为编译器并不真正知道它的实际类型?

So far I've gotten to this point:到目前为止,我已经到了这一点:

public static void main(String[] args) {
        // write your code here
        ArrayList<ClsA> test = new ArrayList<>();
        test.add(new ClsA());
        test.add(new ClsB("t1"));
        test.add(new ClsA());
        test.add(new ClsB("t2"));
        int result = countInstances(test,ClsB.class,true,"t1");
        System.out.println(result);
    }

    public static <T> int countInstances(ArrayList<?> list, Class<T> cls, boolean checkForType, String type) {
        int count = 0;
        for(Object o : list) {
            if(cls.isInstance(o)) {
                if(!checkForType) count++;
                else {}// somehow cast o into the given class (?)
            }
        }
        return count;
    }

Yes, there is cls.cast(o);是的,有cls.cast(o); which will do it, and will give you a T (because the type of cls is Class<T> , and the cast(Object o) method of jlClass is defined to return T . It acts just like the cast operator would, in that it does nothing: It just asserts that o is in fact an instance of this class (so, created as new This() or new SomeSubtypeOfThis() ). If it is, it does nothing. If it is not, it throws ClassCastException. No conversion occurs in any case.它将做到这一点,并会给你一个T (因为cls的类型是Class<T> ,并且jlClasscast(Object o)方法被定义为返回T 。它的行为就像 cast 运算符一样,在那个它什么都不做:它只是断言 o 实际上是这个类的一个实例(因此,创建为new This()new SomeSubtypeOfThis() )。如果是,它什么都不做。如果不是,它抛出 ClassCastException。在任何情况下都不会发生转换。

This isn't useful;这没有用; after all, T is still just object.毕竟,T 仍然只是对象。 This will not give you the power to call getType() on your o - because T has no bounds, T is not going to have any methods other than what java.lang.Object already has.这不会给你在你的o上调用getType()的权力 - 因为T没有边界,T 不会有任何方法,除了java.lang.Object已经拥有的方法。

In general, what you're engaging in is structural typing: It doesn't matter what ClsB is, it just matters that it has a method named getType .一般来说,您从事的是结构类型化: ClsB是什么并不重要,重要的是它有一个名为getType的方法。

This is very bad .这是非常糟糕的

It means that the one method of public interface Camera { public void shoot(Person p); }这意味着public interface Camera { public void shoot(Person p); }的一种方法public interface Camera { public void shoot(Person p); } public interface Camera { public void shoot(Person p); } and public interface Gun { public void shoot(Person p); } public interface Camera { public void shoot(Person p); }public interface Gun { public void shoot(Person p); } public interface Gun { public void shoot(Person p); } are, to such a system, interchangible, and thus you will blow somebody's head off by accident. public interface Gun { public void shoot(Person p); }是,这样的系统,interchangible,这样的话你会意外打击别人的头。

Types (classes, interfaces, etc) are exempt from this problem because they have a namespace - a package header, which serves to make them effectively unique.类型(类、接口等)不受这个问题的影响,因为它们有一个命名空间——一个包头,它可以使它们有效地唯一。 A method should therefore never be considered as meaning anything whatsoever, unless that method is in context of the type it in.因此,永远不应将方法视为任何含义,除非该方法位于其所在类型的上下文中。

Thus, what you COULD do, is something like this:因此,你可以做的是这样的:


public class ClsA {
    public String getType() { .... }
}

public class ClsB extends ClsA { .... }

public static int countInstances(ArrayList<?> list, Class<?> cls) {
    int count = 0;
    for (Object o : list) if (cls.isInstance(o)) count++;
    return count;
}

The above would return '2' for a list with one instance of ClsA and one instance of ClsB, and you pass ClsA.class as second param.对于具有一个 ClsA 实例和一个 ClsB 实例的列表,上面将返回 '2',并且您将ClsA.class作为第二个参数传递。

After all, an instance of ClsB is also an instance of ClsA.毕竟,ClsB 的实例也是 ClsA 的实例。

If you're looking for an answer of '1', you're looking for:如果您正在寻找“1”的答案,那么您正在寻找:

for (Object o : list) {
    if (o != null && o.getClass() == cls) count++;
}

Then for your 'getType' method, we must link that method to an actual type, because otherwise you're shooting people in the face and that's bad.然后对于您的 'getType' 方法,我们必须将该方法链接到实际类型,否则您会朝人们的脸上开枪,这很糟糕。 So, I put the getType() method in ClsA, and then we demand that you pass a list of things which are ClsA's:因此,我将getType()方法放在 ClsA 中,然后我们要求您传递一个属于 ClsA 的事物列表:

public static int countInstancesWithType(List<? extends ClsA> list, String type) {
    int count = 0;
    for (ClsA o : list) {
        if (type.equals(o.getType())) count++;
    }
    return count;
}

Note that this method can be invoked with an ArrayList<ClsA> or an ArrayList<ClsB> - either is fine.请注意,可以使用ArrayList<ClsA>ArrayList<ClsB>调用此方法 - 都可以。 <? extends ClsA> <? extends ClsA> makes that possible; <? extends ClsA>使这成为可能; the ? extends ? extends ? extends is important. ? extends很重要。 Without it, new ArrayList<ClsB>() could not be passed as first parameter.没有它, new ArrayList<ClsB>()无法作为第一个参数传递。

If you want to combine these two ideas, That's.. a bizarre mix of concerns and sounds like you're engaging in the concept of structural typing in java, or otherwise some hacky attempt to make dynamic typing happen.如果您想将这两个想法结合起来,那是.. 一种奇怪的问题组合,听起来好像您正在参与 Java 中结构类型的概念,或者其他一些使动态类型发生的黑客尝试。 Stop doing that;别那样做; java is not that kind of language, and it will hurt the whole time, and the end result will be non-idiomatic, hard to maintain, and hard to read code. java不是那种语言,它会一直伤害,最终的结果将是不惯用的、难以维护的、难以阅读的代码。 Find a java-esque way to do whatever you are doing.找到一种 Java 风格的方式来做你正在做的任何事情。 However, and don't say I didn't warn you:但是,不要说我没有警告你:

public static int countInstancesWithType(List<?> list, String type) {
    int count = 0;
    for (Object o : list) {
        if (!(o instanceof ClsA a)) continue;
        if (type.equals(a.getType())) count++;
    }
    return count;
}
// NB: This uses java15 features. Without java15, you'd have to
// spend an extra line or two to cast ClsA separately.

There is no point trying to generalize ClsA here, because by doing so you remove the ability for your code to be capable of realizing that ClsA instances have a getType() method.在这里尝试概括ClsA是没有意义的,因为通过这样做,您将删除代码能够实现ClsA实例具有getType()方法的能力。

What about this?那这个呢? (see the changed signature of countInstances). (请参阅 countInstances 的更改签名)。

public static void main(String[] args) {
    // write your code here
    ArrayList<ClsA> test = new ArrayList<>();
    test.add(new ClsA());
    test.add(new ClsB("t1"));
    test.add(new ClsA());
    test.add(new ClsB("t2"));
    int result = countInstances(test,ClsB.class,o -> o.getType().equals("t2"));
    // count all
    //int result = countInstances(test,ClsB.class,o -> true);
    System.out.println(result);
}

public static <T> int countInstances(ArrayList<?> list, Class<T> cls, Predicate<T> test) {
    int count = 0;
    for(Object o : list) {
        if(cls.isInstance(o)) {
            if (test.test((T)o)) count++;
        }
    }
    return count;
}

This does not answer your post's title, but I guess it is what you are looking for.这不能回答您帖子的标题,但我想这正是您要找的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM