gpt4 book ai didi

java - 为什么在 Java 中没有删除成员字段的通用类型信息?

转载 作者:行者123 更新时间:2023-12-03 21:07:47 28 4
gpt4 key购买 nike

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class Foo<T> {

public List<Integer> aGenericList;

public T item;

public Foo() {
aGenericList = new ArrayList<>();
}

public static void main(String[] args) throws NoSuchFieldException {
Foo foo = new Foo<String>();
System.out.println(foo.aGenericList.getClass());

Field testField = Foo.class.getField("aGenericList");
Type genericType1 = testField.getGenericType();
System.out.println(genericType1.getTypeName());
}
}
结果是:
class java.util.ArrayList
java.util.List<java.lang.Integer>
这意味着使用反射方法,可以获得删除的类型信息。
现在我的问题是:
  • 这种行为是在 JLS/JVMS 规范中正式定义的(如果是,在哪里?),还是由实现该语言的不同供应商决定?
  • 是否可以将反射方法应用于局部变量 foo得到类似 Foo<java.lang.String> 的东西?
  • 最佳答案

    你的问题
    1. 这种行为是在 JLS/JVMS 规范中正式定义的(如果是,在哪里?),还是由实现该语言的不同供应商决定?
    Java 语言规范似乎专门用于 not describe reflection :

    Consequently, this specification does not describe reflection in any detail.


    而是将反射的完整行为留给 API 记录(即在 Javadoc 中)。
    但是,Java 虚拟机规范确实解释了 generic information must be emitted by a compiler :

    4.7.9. The Signature Attribute

    The Signature attribute is a fixed-length attribute in the attributes table of a ClassFile, field_info, or method_info structure (§4.1, §4.5, §4.6). A Signature attribute records a signature (§4.7.9.1) for a class, interface, constructor, method, or field whose declaration in the Java programming language uses type variables or parameterized types. See The Java Language Specification, Java SE 15 Edition for details about these constructs.

    [...]

    4.7.9.1. Signatures

    Signatures encode declarations written in the Java programming language that use types outside the type system of the Java Virtual Machine. They support reflection and debugging, as well as compilation when only class files are available.

    A Java compiler must emit a signature for any class, interface, constructor, method, or field whose declaration uses type variables or parameterized types. Specifically, a Java compiler must emit:

    • A class signature for any class or interface declaration which is either generic, or has a parameterized type as a superclass or superinterface, or both.

    • A method signature for any method or constructor declaration which is either generic, or has a type variable or parameterized type as the return type or a formal parameter type, or has a type variable in a throws clause, or any combination thereof.

      If the throws clause of a method or constructor declaration does not involve type variables, then a compiler may treat the declaration as having no throws clause for the purpose of emitting a method signature.

    • A field signature for any field, formal parameter, or local variable declaration whose type uses a type variable or a parameterized type.

    [...]


    2. 局部变量 foo是否可以应用反射方式?得到类似 Foo<java.lang.String> 的东西?
    不,因为局部变量不能反射访问。至少不是直接通过 Java 语言。但让我们说他们是。你有:
    Foo foo = new Foo<String>();
    将反射(reflect)的是左侧。这是一个原始类型,所以你只知道 foo 的类型是 Foo .您将无法判断右侧创建的实例是使用 String 参数化的。 .

    一些澄清(希望)
    当我们说“泛型在运行时被删除”时,我们并不是指在这种情况下。静态定义类型的可反射访问结构,例如字段,保存在字节码中。例如,以下内容:
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.lang.reflect.WildcardType;
    import java.util.ArrayList;
    import java.util.List;

    public class Main {

    private static List<? extends Number> list = new ArrayList<Integer>();

    public static void main(String[] args) throws Exception {
    Field field = Main.class.getDeclaredField("list");

    // Due to List being a generic type the returned Type is actually
    // an instance of java.lang.reflect.ParameterizedType
    Type genericType = field.getGenericType();
    System.out.println("Generic Type = " + genericType);

    // The raw type can be gotten from the ParameterizedType. Here the
    // returned Type will actually be an instance of java.lang.Class
    Type rawType = ((ParameterizedType) genericType).getRawType();
    System.out.println("Raw Type = " + rawType);

    // The ParameterizedType gives us access to the actual type
    // arguments declared. Also, since a bounded wildcard was used
    // the returned Type is actually an instance of
    // java.lang.reflect.WildcardType
    Type typeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0];
    System.out.println("Type Argument = " + typeArgument);

    // We know in this case that there is a single upper bound. Here
    // the returned Type will actually be an instance of java.lang.Class
    Type upperBound = ((WildcardType) typeArgument).getUpperBounds()[0];
    System.out.println("Upper Bound = " + upperBound);
    }
    }
    将输出:
    Generic Type  = java.util.List<? extends java.lang.Number>
    Raw Type = interface java.util.List
    Type Argument = ? extends java.lang.Number
    Upper Bound = class java.lang.Number
    所有这些信息都在源代码中。请注意,我们正在反射(reflection)地查看 list 领域 .我们是 不是 查看由所述字段引用的实例(即运行时对象)。知道字段的泛型类型与知道字段的名称是 list 真的没有什么不同。 .
    我们不知道的是 ArrayList参数化为 Integer .将以上内容改为:
    import java.lang.reflect.TypeVariable;
    import java.util.ArrayList;
    import java.util.List;

    public class Main {

    private static List<? extends Number> list = new ArrayList<Integer>();

    public static void main(String[] args) {
    Class<?> clazz = list.getClass();
    System.out.println("Class = " + clazz);

    TypeVariable<?> typeParameter = clazz.getTypeParameters()[0];
    System.out.println("Type Parameter = " + typeParameter);
    }
    }
    输出:
    Class          = class java.util.ArrayList
    Type Parameter = E
    我们可以看到我们知道 list引用的实例是 java.util.ArrayList 的一个实例.但从那里我们可以确定的是 ArrayList类是泛型的,只有一个类型参数 E .我们无法确定 list字段被分配了 ArrayList类型参数为 Integer .换句话说, ArrayList实例本身不知道它声明包含什么类型的元素——该信息已被删除。
    换句话说, list字段的类型在运行时已知,但 ArrayList实例(即在运行时创建的对象)只知道它是一个 ArrayList .

    关于java - 为什么在 Java 中没有删除成员字段的通用类型信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65651242/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com