在Java 8中使用 .class 进行类型转换的问题?

huangapple go评论72阅读模式
英文:

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 8中使用 .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 &quot;cannot find symbol&quot; for the cast method
SampleClass.cast(o);
//sampleClass is an instance of SampleClass
//this method throws error &quot;&lt;identifier&gt; expected&quot;
sampleClass.class.cast(o);
//this method works!
SampleClass.class.cast(o);
//this returns two &quot;&lt;identifier&gt; expected&quot; 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 在Java 8中使用 .class 进行类型转换的问题?

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 &quot;something&quot; 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&lt;Sample&gt;. 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&lt;Class&gt; 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&lt;Sample&gt; sampleClassLiteral = Sample.class;

		final Sample superObject = new Sample();
		// dynamic class
        // `? extends Sample` because the dynamic type could be a subclass
		Class&lt;? extends Sample&gt; 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&lt;? extends Sample&gt; subSampleMethod = subObject.getClass();
		assert subSampleMethod != superClassMethod;

		SubSample staticCast = ((SubSample) subObject);

		List&lt;Object&gt; listOfAny = List.of(superObject, subObject, sampleClassLiteral, &quot;some string&quot;, 12);
		// static type check &amp; casting
		final List&lt;Sample&gt; listOfSample = listOfAny.stream()
				.filter(elem -&gt; elem instanceof Sample) // Sample.class::isInstance
				.map(elem -&gt; (Sample) elem)             // Sample.class::cast
				.collect(toList());

		final List&lt;Sample&gt; samples = listOfTargetClass(listOfAny, Sample.class);
		final List&lt;? extends Sample&gt; sameAsSamples = listOfTargetClass(listOfAny, superClassMethod);
        // [superObject, subObject] : does NOT contain `sampleClassLiteral` because it&#39;s not of type `Sample`, it is of type `Class&lt;Sample&gt;`
		System.out.println(samples);
		System.out.println(sameAsSamples);
		assert samples.equals(sameAsSamples);

		final List&lt;SubSample&gt; subSamples = listOfTargetClass(listOfAny, SubSample.class);
		System.out.println(subSamples);
    }

    static &lt;T&gt; List&lt;T&gt; listOfTargetClass(Collection&lt;?&gt; anyCollection, Class&lt;T&gt; targetClass) {
		// dynamic type check and casting
		return anyCollection.stream()
				.filter(targetClass::isInstance) // obj -&gt; targetClass.isInstance(obj)
				.map(targetClass::cast) // obj -&gt; 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.)

huangapple
  • 本文由 发表于 2020年8月9日 01:45:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/63318502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定