Types vs. Classes
Tags: beginners, inthirtyseconds, java, computerscience
Published: 2020-08-09 20:13:37

Some languages (Java in particular) blur the line between _types_ and _classes_. You may even see them used interchangeably in tutorials, documentation, etc. While they are _related_ concepts, they are not synonymous.

### Here's a 30-second explanation.

Consider [the `Vector` class](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/Vector.html)

```java
jshell> var a = new Vector<Integer>(List.of(1, 2, 3))
a ==> [1, 2, 3]
```

Vector `a` is an instance of the `Vector` class. But its _type_ is not `Vector`, but rather `Vector<Integer>`. A `Vector<Integer>` and (for example) a `Vector<String>` may be instances of the same _class_ (`Vector`), but they are clearly not the same _type_ -- they hold totally different kinds of data!

In addition, `Vector` cannot be a type, because it _takes_ a type parameter itself. When we write `Vector`, we actually mean `Vector<E>`, where `E` is a _type parameter_.

We can draw a parallel with constructor arguments. Consider this simple class

```java
jshell> public class Dog {
   ...>   private String _name;
   ...>   public Dog(String name) {
   ...>     _name = name;
   ...>   }
   ...>   public String name() { return _name; }
   ...> }
|  modified class Dog

jshell> var Fido = new Dog("Fido")
Fido ==> Dog@68de145

jshell> var Spot = new Dog("Spot")
Spot ==> Dog@46f7f36a
```

You can think of class `Dog` as a sort of _parameterized object constructor_. It takes a single parameter (or "argument"), `name`, and uses that `name` to construct an object, a `Dog`.

Similarly, generic classes like `Vector<E>` can be thought of as _parameterized type constructors_. They take a single parameter, which in this case is another type, and use that type to construct a new (_parameterized_) type.

### So why is this so confusing in Java?

Because Java uses [_raw types_](https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html), which you may occasionally see in compiler or `jshell` warnings

```java
jshell> var b = new Vector(List.of(1, 2, 3))
|  Warning:
|  unchecked call to Vector(java.util.Collection<? extends E>) as a member of the raw type java.util.Vector
|  var b = new Vector(List.of(1, 2, 3));
|          ^--------------------------^
b ==> [1, 2, 3]
```

Java will grudgingly compile this code, but since you didn't tell it what type `E` is, [it assumes it to be `Object`](https://stackoverflow.com/a/2770692/2925434). Look what happens when I try to add a `String` to `b`

```java
jshell> b.add("hey")
|  Warning:
|  unchecked call to add(E) as a member of the raw type java.util.Vector
|  b.add("hey")
|  ^----------^
$23 ==> true

jshell> b
b ==> [1, 2, 3, hey]
```

Java can't narrow the _type_ of the elements within the `Vector` at all. All it knows is that they must be some kind of `Object`s. Since `String` is an `Object`, it has no problem adding it to this `Vector`.

If you try the same with `a`, you'll get an error

```java
jshell> a.add("hey")
|  Error:
|  incompatible types: java.lang.String cannot be converted to java.lang.Integer
|  a.add("hey")
|        ^---^
```

Raw types are a holdover from a time before Java had these type parameterizations ([nearly two decades ago](https://en.wikipedia.org/wiki/Generics_in_Java) now). But they still regularly cause confusion among the uninitiated as to the difference between a _type_ and a _class_ in Java.

Remember that a `Vector<String>` and a `Vector<Integer>` are both `Vector`s (they are instances of the same _class_), but they do not hold the same kind of data, so they do not have the same _type_.