Java泛型-类型推断
考虑以下几点:Java泛型-类型推断,java,generics,Java,Generics,考虑以下几点: public class GenericTest { static void print(int x) { System.out.println("Int: " + x); } static void print(String x) { System.out.println("String: " + x); } static void print(Object x) { System.ou
public class GenericTest {
static void print(int x) {
System.out.println("Int: " + x);
}
static void print(String x) {
System.out.println("String: " + x);
}
static void print(Object x) {
System.out.println("Object: " + x);
}
static <T> void printWithClass(T t) {
print(t);
}
public static void main(String argsp[]) {
printWithClass("abc");
}
}
公共类泛型测试{
静态无效打印(int x){
System.out.println(“Int:+x”);
}
静态无效打印(字符串x){
System.out.println(“字符串:+x”);
}
静态无效打印(对象x){
System.out.println(“对象:+x”);
}
静态无效打印WithClass(T){
打印(t);
}
公共静态void main(字符串argsp[]){
打印类(“abc”);
}
}
它打印对象:abc。
为什么不打印String:abc?Java支持方法重写(动态类型绑定),但不支持您试图实现的功能(重载是静态多态性,而不是动态的) 为了在Java中实现您想要实现的目标,您需要双重分派 访客模式应该是你在这里的朋友 我已经为您编写了一个代码示例
public class Test {
public static void main(String argsp[]) {
PrintTypeImpl typeImpl = new PrintTypeImpl(new StringType(), new IntType(), new ObjectType());
typeImpl.accept(new PrintVisitor());
}
static final class PrintVisitor implements TypeVisitor {
public void visit(IntType x) {
System.out.println("Int: ");
}
public void visit(StringType x) {
System.out.println("String: ");
}
public void visit(ObjectType x) {
System.out.println("Object: ");
}
}
interface TypeVisitor {
void visit(IntType i);
void visit(StringType str);
void visit(ObjectType obj);
}
interface PrintType {
void accept(TypeVisitor visitor);
}
static class StringType implements PrintType {
@Override
public void accept(TypeVisitor visitor) {
visitor.visit(this);
}
}
static class ObjectType implements PrintType {
@Override
public void accept(TypeVisitor visitor) {
visitor.visit(this);
}
}
static class IntType implements PrintType {
@Override
public void accept(TypeVisitor visitor) {
visitor.visit(this);
}
}
static final class PrintTypeImpl implements PrintType {
PrintType[] type;
private PrintTypeImpl(PrintType... types) {
type = types;
}
@Override
public void accept(TypeVisitor visitor) {
for (int i = 0; i < type.length; i++) {
type[i].accept(visitor);
}
}
}
}
公共类测试{
公共静态void main(字符串argsp[]){
PrintTypeImpl-typeImpl=新的PrintTypeImpl(新的StringType(),新的IntType(),新的ObjectType());
typeImpl.accept(新的PrintVisitor());
}
静态最终类PrintVisitor实现了TypeVisitor{
公共无效访问(IntType x){
System.out.println(“Int:”);
}
公共无效访问(StringType x){
System.out.println(“字符串:”);
}
公共无效访问(ObjectType x){
System.out.println(“对象:”);
}
}
界面类型访问者{
无效访问(i型);
无效访视(StringType str);
无效访问(ObjectType obj);
}
接口打印类型{
无效接受(输入访客);
}
静态类StringType实现PrintType{
@凌驾
公共无效接受(类型访问者){
访客。访问(本);
}
}
静态类ObjectType实现PrintType{
@凌驾
公共无效接受(类型访问者){
访客。访问(本);
}
}
静态类IntType实现PrintType{
@凌驾
公共无效接受(类型访问者){
访客。访问(本);
}
}
静态最终类PrintTypeImpl实现PrintType{
PrintType[]类型;
私有PrintTypeImpl(PrintType…类型){
类型=类型;
}
@凌驾
公共无效接受(类型访问者){
for(int i=0;i
因为java泛型不像您想象的那样是泛型。当编译泛型java代码时,所有类型信息实际上都被剥离,只剩下基本的已知类型。在这种情况下,类型是对象
java中的泛型实际上只是编译器的一种伎俩,编译器会删除本来必要的强制转换,并导致编译时限制。最后,当它被编译成字节码时,剩下的就是基类型
此过程称为类型擦除。这有助于理解实际发生的情况。因为它只能在运行时知道这一点,但实际上,由于java是一种编译语言而不是脚本语言,所以它取决于编译时间 java泛型允许“一个类型或方法在提供编译时类型安全性的同时对各种类型的对象进行操作。” 您当然可以尝试以下方法:
static <T extends String> void printWithClass(T t) {
print(t);
}
static void printWithClass(T){
打印(t);
}
虽然这不是你想要的,但这是不可能的,因为编译器正在发号施令。这是因为:你的
平心而论,这种“语法糖”让编译器能够进行一些非常好和重要的检查,但在运行时只有一个printWithClass
方法的副本,它使用java.lang.Object
作为变量t
的类型
如果你已经体验过其他语言的泛型(C++,C++模板,艾达)类型擦除会与你所知道的相反,但是这是它在封面下工作的方式。
< p>泛型由编译器解释,并且他们执行附加类型检查来避免任何运行时的铸造问题。泛型类型信息为。因此,在运行时printWithClass接收的只是对象而不是字符串,因此是结果。这与类型擦除无关,这是一个编译问题,如果JVM在运行时存储泛型方法,也会发生同样的情况。它也不是关于类型推断——编译器会像您预期的那样推断
static <T> void printWithClass(T t) {
print(t);
}
问题是,当编译器为
printWithClass
生成代码时,它需要一个特定的方法签名来与print
调用关联。Java没有多重分派,因此它不能在方法表中放置模糊的签名,并决定在运行时调用什么在T
上唯一的上界是对象
,因此唯一匹配的方法是打印(对象)
额外示例以澄清:
public class OverloadingWithGenerics {
static void print(Integer x) {
System.out.println("Integer: " + x);
}
static void print(Double x) {
System.out.println("Double: " + x);
}
static void print(Number x) {
System.out.println("Number: " + x);
}
static <T extends Number> void printWithClass(T t) {
print(t);
}
public static void main(String argsp[]) {
printWithClass(new Integer(1234));
}
}
请看这个关于获取T类型的问题,它不是关于类型擦除,而是关于编译时可用的泛型边界。如果我们使用
,则输出是String:abc
@Daniel绝对-因为该方法将变成静态void printWithClass(String t)
。但它仍然是一个单一的方法,具有单一的类型,在编译时绑定以调用静态print
方法的单一重载。
static <T> void printWithClass(T t) {
print(t);
}
static void printWithClass(Object t) {
print(t);
}
public class OverloadingWithGenerics {
static void print(Integer x) {
System.out.println("Integer: " + x);
}
static void print(Double x) {
System.out.println("Double: " + x);
}
static void print(Number x) {
System.out.println("Number: " + x);
}
static <T extends Number> void printWithClass(T t) {
print(t);
}
public static void main(String argsp[]) {
printWithClass(new Integer(1234));
}
}
Number: 1234