In Java it’s important to know what references are and how they are used. So it’s important to know what operations can be performed on references.
The Question
To make the question clearer:
- Operation: anything that the language offers (operators, statements etc)
- Reference: Any expression that has a reference type (not primitive)
Some operations use reference type expressions, but only allow certain types.
I think this is helpful if you study how Java really works and how references are different from primitives.
Note that I write this in 2015 and we don’t have value types yet. A future version of Java might introduce them. When type values are introduced I’ll update this post (if I don’t forget).
The Answer
I use foo
like a variable name and it always represents a reference type expression. So foo
could be replaced with anything that is a reference.
For example a String literal: "foo"
or a method call: bla.toString()
Operations on all Reference Types
Some of them depend on the context of code. In Java all types are checked (except some generic type information). But these operations are not restricted by anything other than regular type checking. If the type is Object, then everything goes.
-
The “.” Operator (member access):
foo.member;
foo.method();
This includes.new
, iffoo
is an outer object:
foo.new NestedClass()
And you can call static members:
foo.staticMethod()
-
The “::” Operator (method reference):
Supplier s = foo::getBar;
-
The “=” Operator (assignment)
Foo foo = new Foo();
Foo foo2 = foo;
-
The “+” Operator (concatenation):
String s = "foo: " + foo;
This really usesfoo.toString()
. So it implicitly uses the dot operator. And it only works if at least one expression is a String. -
The “==”/”!=” Operators (equality):
if (foo == null) { ... }
if (foo != null) { ... }
-
Type Casting:
(Bar) foo
This just tells the compiler that
foo
is expected to be an instance ofBar
, but doesn’t really do anything at runtime. You still get an exception iffoo
is not an instance ofBar
. -
Type Comparison Operator:
if (foo instanceof Bar) { ... }
Update: Since Java 19 we have record patterns:
if (foo instanceof Pair(var left, var right)) { ... }
and
leftright
are then two new references. -
Concurrency:
synchronize(foo) { ... }
-
Construction:
This doesn’t do anything with a reference, but it creates one.
new Foo()
-
Pass-By-Value:
xyz.method(foo);
new Bla(foo);
-
Return Statement:
return foo;
Operations on certain Reference Types
The restrictions are defined by the Java Language Specification.
-
Array Access Expression (array types):
foo[i]
-
Array Initializer and Creation Expression (array types):
Like constructor calls, they create a new object and therefore a reference:
Object[] a1 = { f, o, o };
Foo[] a2 = new Foo[42];
-
Lambda (functional interface):
The lambda itself is an expression. So this creates a new reference to a single abstract method type:
(param) -> param.bla()
An even simpler example is this, which could be used as aRunnable
, that doesn’t do anything:
() -> {}
-
String Literals (String):
They also create a reference to the cached String.
"foo"
-
Auto Unboxing (only if wrapper type):
int i = foo;
foo > 8
foo++
etc. -
Switch Statement (Enums and String):
switch(foo) { ... }
Update: Since Java 12 we have “Enhanced Switch Expressions”. And they kept improving on the new ways of using switch. But it still takes one value (possibly a reference and maybe even null). -
Case (String or enum type):
“bla” is of reference type (String):
case "bla": ...
the enum constant FOO is of ref. type:
case MyEnum.FOO:
Update: Since Java 12 we have “Enhanced Switch Expressions”. But that doesn’t really add more operations. There are just more things you can do in a “case”, such ascase String s && s.length()>3 -> ...
andÂcase null -> ...
-
For-Each (Iterable):
for(Type e : foo) { ... }
-
Try-With-Resource (AutoCloseable):
The expression must be a variable declaration with initialization.
try(Foo foo = new Foo()) { ... }
-
Throwing (Throwable)
This also depends on the throws clause.
throw foo;
-
Catching (Throwable):
This also depends on the throws clauses of called methods.
try { ... } catch (Foo foo) { ... }
Miscellaneous
-
this
/super
KeywordsIn Java you can use
this
andsuper
for different things. They are references (unless used for constructor chaining) and behave like variables/parameters. You can even addthis
as a parameter so you can add annotations to it (the so called receiver parameter). -
class
KeywordThis is used like a static field of each class to get a reference to that class. Use
Foo.class
to get the same asfoo.getClass()
but without needing a reference to an instance ofFoo
. This even works on primitives (int.class
).
One thought on “What Operations can be performed on a Reference in Java?”