-2

I have these classes with the method:

public abstract class Bar<T extends Bar> {
    Foo myFoo;
    public Optional<Foo> findFoo() { return Optional.ofNullable(this.myFoo); }
}

public class Baz extends Bar<Baz> {
}

, where Foo is a concrete final class and o is an object that extends Bar.

It ok to get the value in my unit test this way:

Bar bar = new Baz();
Optional<Foo> optinalFoo =  bar.findFoo();
Foo foo = optionalFoo.get();

However, when called directly the type information is lost:

Foo foo = bar.findFoo().get();

In the second example the compiler thinks get() returns an Object instead of a Foo. Why? Is there a way to provide the type information to the compiler in some other way?

(I know that you should avoid calling get() directly but since this is in a unit test it's ok if it throws on unexpected results.)

barksten
  • 578
  • 4
  • 12
  • 3
    Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a [mcve]. Specifically: what is **o** ? – GhostCat Apr 24 '17 at 08:26
  • 4
    Is `Foo` a generic type or a concrete one? Having "some class with a method" is not descriptive enough for us to understand the issue or reproduce the problem. – E_net4 Apr 24 '17 at 08:27
  • 1
    it won't compile due to `return.ofNullable`. what does it mean? – Andrew Tobilko Apr 24 '17 at 08:28
  • Works for me, what exactly is `o`? – kalsowerus Apr 24 '17 at 08:33
  • I have updated the example for completeness. The key seems to be related to the generic inheritance. – barksten Apr 24 '17 at 08:56
  • 1
    Possible duplicate of [What is a raw type and why shouldn't we use it?](http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it) – Tom Apr 24 '17 at 09:16

2 Answers2

0

Bar bar is a raw type. Raw types don't have any generic information, it's an all or nothing thing. There isn't a nice, kind of generic fall back. An example is

Map<String, String> map = new HashMap<>();
Set<Map.Entry<String, String>> entries = map.entrySet();

// however when you use a raw type there is no generic.
Map map2 = new HashMap();
Set<Map.Entry> entries2 = map2.entrySet(); // doesn't work
Set entries2 = map2.entrySet(); // does work

This is because raw types are provided for backward compatibility only. In versions before Java 5.0 there was no generic and so you had to expect raw type didn't have any generics.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
0

The bar variable uses raw type, so it lacks all generic type checks. Defining type Optional<Foo> optionalFoo you also have unchecked assignment (it means types will be checked run-time only), but compiler sees the type and the .get() works fine. To fix you need to define generic parameter, e.g.

Bar<? extends Bar> bar = new Baz();
kan
  • 28,279
  • 7
  • 71
  • 101