What Is a Class Literal in Java

What is a class literal in Java?

Class<String> c = String.class;

Check out the Javadoc for java.lang.Class to see what you can do with one of these little guys - mostly related to reflection

what exactly is the type of class literal in Java?

what exactly is the type of class literal in Java?

The erased type is java.lang.Class.

The non-erased type of Foo.class would be java.lang.Class<Foo>.


The reason it is in the JLS as a primary expression is technical:

  • A class literal is not a unitary literal. It is three (or more) distinct symbols that combine to form this "constanty, literally sort of thing".

  • They decided to call it a literal because the value is a constant.

  • From a syntactic point of view it has to go into the same part of the grammar as the (other) primary expressions ... in order for the grammar to describe the language without a mass of ambiguity / context sensitivity.

So it really could go in either place in the JLS. But they have to put it in only one place. And since the other literals in the Literal section are unitary (i.e. one symbol), it makes sense to put it into the Primary Expression section.

But the bottom line is that it doesn't really matter why they decided to organize the JLS that way. The meaning of a class literal does not depend in where it is specified.

How to understand java class literals?

String.class is a primary expression which does not decompose into operands and operators, but that doesn't stop it from having internal syntactic structure. I am sure you will agree that " is not an operator, either, yet "i am a string" is a literal expression.

Class literal with generics in java

First things first.

  1. I can only pass List.class or Map.class instead of also specifying the
    generic type. Based on that the result type is determined
    (implementation details are not provided).

You cannot specify the generic type in the class parameter because (Read this carefully) The generic type information is not present during the runtime. At runtime, you do not get List<String> or List<Integer> etc. At runtime, everything is just plain List.


A brief history on why it is like that.

Generics did not exist until Java 5. So when generics was introduced as a part of Java 5, the last thing they wanted to do was to tell the whole world to change from List to List<String> or List<Whatever_Object_They_Want>.

For example, let's say you are using a dependency which was compiled using Java 4, and a method in this dependency which returns just plain old List, you can still call that method using your code, which is compiled in Java 5. Only thing is you cannot cast it to any generic type.

Imagine if Java5 started supporting only generic types like List<> and not the plain old List. You would have to depend on all the vendors to provide the dependency which is compiled in Java5. This would cause chaos. So to avoid this, and to maintain backward compatibility with those using previous versions of java, the generic type information is stripped off when the code is compiled to byte code. This is called Type Erasure.

It is because of this reason, you cannot specify the generic type with class literals of any collection type.


Coming to your second point


  1. Since, the result type is derived using class literal i am getting the following compile time errors.

Type mismatch: cannot convert from List<Set<String>> to List<T>


Type mismatch: cannot convert from List<Map<String,Object>> to List<T>

If you go through the Generics documentation, the generic type List is different from List< Map< String, Object >>>. (That is why we have generics in Java. Eg., List<String> is different from List<Object>. You cannot cast List<String> to List<Object>)

However, since you want to return List<Map<>> in some cases and List<Set<>> in some other cases depending on the parameter, I suggest you to change the return type of the method serve to List<? extends Collection>

Using List<? extends Collection> as a return type/method argument means that this list can be a List of any of the subclasses of Collection. Please have a look at the hierarchy to get more information.

Hope this helped!

How do I express an class literal for an Array in Java?

The correct way is using the .class.

Examples:

int[].class
Long[].class

These will do exactly what you need.

Java Class Literals and Reflection?

A class literal is something like String.class, i.e. a compile-time literal representing the String class.

In short, reflection is a language feature that allows you to "reflect" on the code, i.e. you can query the system for classes, methods, fields, etc. and use that data to create new instances, call methods or change the value of fields.

Reflection might be useful to create objects of classes that are not known at compile-time, but are on the classpath at runtime. Several extension frameworks make use of that, mostly by providing fully qualified class names in some text file (e.g. com.acme.SomeFancyClass), getting the associated Class object from the class loader and creating new instances.

Other frameworks (e.g. Apache Common's builder objects, OGNL, Java Beans etc.) use reflection to query the available properties (getters and/or matching setters) that can be accessed (through calls to those getters/setters).

However, if you are new to Java, I'd recommend diving into other language features before loosing yourself in the depth of the reflection facility.

Where is .class defined in Java? (Is it a variable or what?)

That's implemented internally and called a class literal which is handled by the JVM.

The Java Language Specification specifically mentions the term "token" for it.

So .class is more than a variable, to be frank it is not a variable at all. At a broader level you can consider it as a keyword or token.

https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.8.2

A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a '.' and the token class.

A class literal evaluates to the Class object for the named type (or for void) as defined by the defining class loader (§12.2) of the class of the current instance.

@Target Attribute value must be a class literal

You used the wrong @Target. You meant to use java.lang.annotation.Target but imported org.hibernate.annotations.Target. Change the first import to import java.lang.annotation.Target and it should work fine.



Related Topics



Leave a reply



Submit