英文:
Issue casting with .class in Java 8?
问题
我以为 .class 是被调用的对象的类。但是这与我尝试做的程序不符。我将给出一些示例。
// o 是 Object 类型
// 这个方法会抛出错误 "无法找到符号" 来自于 cast 方法
SampleClass.cast(o);
// sampleClass 是 SampleClass 的实例
// 这个方法会抛出错误 "<标识符> 期望"
sampleClass.class.cast(o);
// 这个方法有效!
SampleClass.class.cast(o);
// 这会返回两个 "<标识符> 期望" 错误
sampleClass.class.class.cast(o);
// 这也有效!
((SampleClass) o)
我以前以为 sampleClass.class == SampleClass
,是 Class 类型的对象。我还以为 SampleClass.class
会返回一些非常抽象的东西,难以理解。现在我知道我实际上什么都不知道。感谢帮助解决这个难题的任何帮助
编辑:谢谢大家!我很高兴能够学到关于Java的知识。我感激你们的帮助。
英文:
I thought that .class was the class of the object it was being called on. However this does not fit with what I was trying to do with a program. I'll give some examples.
//o is of type Object
//this method throws error "cannot find symbol" for the cast method
SampleClass.cast(o);
//sampleClass is an instance of SampleClass
//this method throws error "<identifier> expected"
sampleClass.class.cast(o);
//this method works!
SampleClass.class.cast(o);
//this returns two "<identifier> expected" errors
sampleClass.class.class.cast(o);
//this works too!
((SampleClass) o)
I previously thought that sampleClass.class == SampleClass, an object of type Class. I also thought that SampleClass.class would return something really meta that's hard to think about. Now I know that I don't really know anything. Any help solving this conundrum is appreciated
Edit: Thanks everyone! I'm happy to be learning this about Java. I'm grateful for the help
答案1
得分: 6
我已经编写了一些可编译的Java代码,可能可以澄清一些有关Class和类型转换的用法。希望它足够自我说明。
你可以将Sample.class
看作是与"something"
是字符串字面量一样的"类字面量"。它是一个表达式,有一个值,可以分配给一个变量,它是一个对象。这个对象的类型是Class<Sample>
。另一方面,Sample
是一个类型,而不是一个表达式,你不能将它分配给一个变量。
Class
是一个元类,即它是描述另一个类的类。你不能比Class<Class>
更元。有趣的是:还有原始类字面量,如int.class
。
class Main {
public static void main(String[] args) {
// 类字面量
Class<Sample> sampleClassLiteral = Sample.class;
final Sample superObject = new Sample();
// 动态类
// `? extends Sample`因为动态类型可能是子类
Class<? extends Sample> superClassMethod = superObject.getClass();
// 类可以通过==和equals进行比较,因为`Class`是final的,它不会覆盖默认的equals实现
assert sampleClassLiteral == superClassMethod;
assert sampleClassLiteral.equals(superClassMethod);
Sample subObject = new SubSample();
// 动态类可以与变量的静态类型不同
Class<? extends Sample> subSampleMethod = subObject.getClass();
assert subSampleMethod != superClassMethod;
SubSample staticCast = ((SubSample) subObject);
List<Object> listOfAny = List.of(superObject, subObject, sampleClassLiteral, "some string", 12);
// 静态类型检查和转换
final List<Sample> listOfSample = listOfAny.stream()
.filter(elem -> elem instanceof Sample) // Sample.class::isInstance
.map(elem -> (Sample) elem) // Sample.class::cast
.collect(toList());
final List<Sample> samples = listOfTargetClass(listOfAny, Sample.class);
final List<? extends Sample> sameAsSamples = listOfTargetClass(listOfAny, superClassMethod);
// [superObject, subObject]:不包含`sampleClassLiteral`,因为它不是`Sample`类型,而是`Class<Sample>`类型
System.out.println(samples);
System.out.println(sameAsSamples);
assert samples.equals(sameAsSamples);
final List<SubSample> subSamples = listOfTargetClass(listOfAny, SubSample.class);
System.out.println(subSamples);
}
static <T> List<T> listOfTargetClass(Collection<?> anyCollection, Class<T> targetClass) {
// 动态类型检查和转换
return anyCollection.stream()
.filter(targetClass::isInstance) // obj -> targetClass.isInstance(obj)
.map(targetClass::cast) // obj -> targetClass.cast(obj)
.collect(toList());
}
static class Sample { }
static class SubSample extends Sample { }
}
英文:
I have put together some compilable Java code that can maybe clarify some usage of Class and casting. Hopefully it is self-documenting enough.
You can think of Sample.class
as a "class literal" in the same way "something"
is a string literal. It is an expression, it has a value, it is assignable to a variable, it is an object. The type of this object is Class<Sample>
. On the other hand Sample
is a type, not an expression, you cannot assign it to a variable.
Class
is a meta-class, i.e. it is a class which desribes another class. You cannot go more meta than Class<Class> classClass = Class.class;
. Interesting thing: there are also primitive class literals like int.class
.
class Main {
public static void main(String[] args) {
// class literal
Class<Sample> sampleClassLiteral = Sample.class;
final Sample superObject = new Sample();
// dynamic class
// `? extends Sample` because the dynamic type could be a subclass
Class<? extends Sample> superClassMethod = superObject.getClass();
// classes are comparable both by == and equals, because `Class` is final and it does not override the default equals implementation
assert sampleClassLiteral == superClassMethod;
assert sampleClassLiteral.equals(superClassMethod);
Sample subObject = new SubSample();
// dynamic class can be different from the static type of the variable
Class<? extends Sample> subSampleMethod = subObject.getClass();
assert subSampleMethod != superClassMethod;
SubSample staticCast = ((SubSample) subObject);
List<Object> listOfAny = List.of(superObject, subObject, sampleClassLiteral, "some string", 12);
// static type check & casting
final List<Sample> listOfSample = listOfAny.stream()
.filter(elem -> elem instanceof Sample) // Sample.class::isInstance
.map(elem -> (Sample) elem) // Sample.class::cast
.collect(toList());
final List<Sample> samples = listOfTargetClass(listOfAny, Sample.class);
final List<? extends Sample> sameAsSamples = listOfTargetClass(listOfAny, superClassMethod);
// [superObject, subObject] : does NOT contain `sampleClassLiteral` because it's not of type `Sample`, it is of type `Class<Sample>`
System.out.println(samples);
System.out.println(sameAsSamples);
assert samples.equals(sameAsSamples);
final List<SubSample> subSamples = listOfTargetClass(listOfAny, SubSample.class);
System.out.println(subSamples);
}
static <T> List<T> listOfTargetClass(Collection<?> anyCollection, Class<T> targetClass) {
// dynamic type check and casting
return anyCollection.stream()
.filter(targetClass::isInstance) // obj -> targetClass.isInstance(obj)
.map(targetClass::cast) // obj -> targetClass.cast(obj)
.collect(toList());
}
static class Sample { }
static class SubSample extends Sample { }
}
答案2
得分: 2
我之前以为 sampleClass.class == SampleClass
,是类型为 Class
的对象。
你几乎说对了。正确的理解是 sampleClass.getClass() == SampleClass.class
,是类 Class
的一个实例。
SampleClass
本身是一种类型,而不是一个值。(在Java中,这是一个明确的区别。)
英文:
> I previously thought that sampleClass.class == SampleClass, an object of type Class.
You were very close. The correct understanding is that sampleClass.getClass() == SampleClass.class
, an instance of the class Class
.
SampleClass
itself is a type, not a value. (In Java that's a firm distinction.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论