2

I went searching to learn how to do lambda expressions in Java, but instead a confusion came up for me. So my understanding of an anonymous class is this:

public class SomeObject {
   public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add(new SomeObject());
   }

}

I saw the term anonymous inner class before, but at that time, I didn't know what a regular anonymous class was. Lot of threads and videos I'm seeing seem to call anonymous inner classes just "anonymous classes." Are they synonymous? My understanding of anonymous inner class is:

 public class Rectangle {
 private double length;
 private double width;
 private double perimeter;

    public void calculatePerimeter() {
    perimeter = (2*length) +(2*width);
   }

     public static void main(String[] args) {
       Rectangle square = new Rectangle() {
        public void calculatePerimeter() {
            perimeter = 4*length;
        }
    };
   }

  }

So essentially, instead of having to write a subclass for Square, and then override the calculatePerimeter() method, I can just make a one-time square class, and override the method in their. Is this correct?

So, anonymous inner classes have to do with inheritance. I'm not understanding the use of it though. Perhaps, it's because I've never used them before, or because I don't have much programming experience. Can you can give me examples or explain when it's useful?

UPDATE: When I moved my code for the anonymous inner class to an IDE, I learned that there are errors; So apparently, the "square" doesn't even inherit the fields of the rectangle. Doesn't this make it even more useless?

Would the equivalent be:

public class Rectangle {
 private double length;
 private double width;
 private double perimeter;

    public void calculatePerimeter() {
    perimeter = (2*length) +(2*width);
   }
 }


public class Square extends Rectangle {
   @Override   
   public void calculatePerimeter() {
      perimeter = 4*getLength();
   }

  public double getLength() {
    return length;
  }



    }
Abdul
  • 997
  • 2
  • 19
  • 37
  • 1
    If you want subclasses to have access to fields, make them `protected` instead of `private`. If a class makes its field `private`, it is saying "These fields are internal details of how I implement my methods. So I don't want anybody mucking with them, not even my subclasses. And they could be removed at any time, or the meaning can be changed, so I don't want anybody using them and depending on their values because they will regret it later when my internal methods change." – ajb Mar 29 '14 at 01:53
  • I did not see that, thank you. But even so, when I write a new subclass, it inherits those private instance variables. In the case of the anonymous inner class, it didn't. – Abdul Mar 29 '14 at 01:58
  • 1
    You say, "When I write a new subclass, it inherits private instance fields". It really doesn't, technically, but did you declare the subclass _inside_ the superclass? Even private instance fields can be accessed under some conditions, so it would make it look like the fields were inherited even though they weren't. Could you post the code where it looks like private instance variables are inherited? It would be instructive. – ajb Mar 30 '14 at 01:42
  • @ajb No, my subclasses weren't inside the superclass. I'd have a rectangle superclass that would have the declared instance variables of length and width. The rectangle constructor would have arguments asking for them. When I would make a square subclass, I would not declare the same instance variables. My square subclass constructor would ask for the same arguments and set them to it. So from that case I'd assume the fields were inherited since I never declared them in the subclass, yet I'd be able to set them through the constructor. – Abdul Mar 30 '14 at 05:34
  • @ajb but then, I don't know about the under the hood stuff. And you're right that they're never inherited, so my observation was wrong. I think this explains it well: http://stackoverflow.com/a/10491050/3040381 – Abdul Mar 30 '14 at 05:34

3 Answers3

6

So my understanding of an anonymous class is this:

public class SomeObject {
   public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add(new SomeObject());
   }
}

There is no anonymous class there. The class SomeObject has a name ... therefore it is not anonymous. In fact, it is just a normal (non-nested, non-inner, non-anonymous) Java class.


I saw the term anonymous inner class before, but at that time, I didn't know what a regular anonymous class was.

There is no such thing as a "regular anonymous class". All Java anonymous classes are "inner".

As the JLS says:

"An inner class is a nested class that is not explicitly or implicitly declared static.

Inner classes include local (§14.3), anonymous (§15.9.5) and non-static member classes (§8.5)."


So, anonymous inner classes have to do with inheritance.

Anonymous inner classes do involve inheritance, but that's not what makes them "inner". See above.


I meant the "list.add(I meant the "list.add(new SomeObject());". All this time, I thought the object you added to the ArrayList, was called an anonymous class since we didn't name it.);". All this time, I thought the object you added to the ArrayList, was called an anonymous class since we didn't name it.

You are incorrect. An object is not a class1.

The new SomeObject() is creating an object, not a class. But that's just normal. Objects / instances don't have names ... as far as the JLS is concerned.

Now variables and fields have names ... but variables are not objects / instances or classes. They are bindings between a name and a slot that can hold a reference to an object (if that's what the type declaration allows).

1 - except in the case of instances of java.lang.Class ... and even then the object is not actually the class / type from a theoretical standpoint.


Or is it called simply an anonymous object and I had two mixed up?

Nope. Objects don't have names. All Java objects are "anonymous". It is not a useful distinction to make. (And see above where I talk about variables ...)


As for your Rectangle / Square examples, they have nothing to do with anonymous classes, inner classes, nested classes or anything like that. They are just top-level classes, using ordinary Java inheritance. (Not that I'm suggesting there is another "non-ordinary" kind of inheritance ...)

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096
  • I meant the "list.add(new SomeObject());". All this time, I thought the object you added to the ArrayList, was called an anonymous class since we didn't name it. Or is it called simply an anonymous object and I had two mixed up? – Abdul Mar 29 '14 at 01:48
  • @Abdul Well, it's not a class, so it can't be an anonymous class, I guess. – Dave Newton Mar 29 '14 at 01:58
  • I apologize, I have no idea why in my mind I had been calling it an anonymous class all this time. Would it be correct to call it an anonymous object? – Abdul Mar 29 '14 at 02:01
  • 1
    @Abdul Theoretically you could, but the term is never used. It's simply an object whose reference isn't saved in the local context (it is, of course, saved in the list). – chrylis -cautiouslyoptimistic- Mar 29 '14 at 02:05
  • @chrylis - The reason it is not used is that it is not useful. If you model a variable name as an object name, then assigning to a variable is potentially adding, changing or removing "names" of objects. That is not a helpful / useful way to think about the behaviour of a program ... especially a complicated one. – Stephen C Mar 29 '14 at 02:11
  • @StephenC so anonymous classes are useful if you want to override an existing method, but don't want to create a new class for just that? – Abdul Mar 29 '14 at 02:18
  • @StephenC That's why I said you *theoretically* could. Technically, I'm more inclined to identify the reference itself as the object's name, meaning that there aren't any anonymous objects at all. – chrylis -cautiouslyoptimistic- Mar 29 '14 at 02:19
  • 1
    @chrylis - The trouble is that you seemed to be saying "you could say that". But a better response would be "you could say that, but you would be >>WRONG< – Stephen C Mar 29 '14 at 02:23
  • @StephenC What's the advantage of doing that over just making another method and naming it differently? The amount of code seem to be similar. – Abdul Mar 29 '14 at 02:26
  • @Abdul - One advantage is that you don't need to look somewhere else. Another is that an inner class can refer to local variables in enclosing scopes ... provided that they are `final`. It turns out that the latter is syntactic sugar, but it *does* make the code significantly simpler. – Stephen C Mar 29 '14 at 02:31
  • @StephenC And the lambda syntactic sugar should make it even easier, a la Ruby closures. – chrylis -cautiouslyoptimistic- Mar 29 '14 at 02:54
2

First off - square can access fields in Rectangle. You need to mark them protected not private

public class Rectangle {
    protected double length;
    protected double width;
    protected double perimeter;

    public void calculatePerimeter() {
        perimeter = (2*length) +(2*width);
    }

    public static void main(String[] args) {
        Rectangle square = new Rectangle() {
            public void calculatePerimeter() {
                perimeter = 4*length;
            }
        };
    }

}

Here are some good descriptions of Inner Classes, Anonymous and local

There are two additional types of inner classes. You can declare an inner class within the body of a method. These classes are known as local classes. You can also declare an inner class within the body of a method without naming the class. These classes are known as anonymous classes.

Local classes are classes that are defined in a block, which is a group of zero or more statements between balanced braces. You typically find local classes defined in the body of a method.

Anonymous Classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.

I think the relevance of Anonymous classes comes when you are designing an API. You could create concrete classes to implement every bit of logic for every interface/abstract class but that would create tons of dependencies and you would still be missing some logic. A great example of anonymous classes is when using predicates for filtering. Like in Google Guava

Lets say I have a List<Integer> and I want to filter the numbers remove the 1s and return a new list

public static List<Integer> filter(List<Integer> input) {
   List<Integer> rtn = new ArrayList<Integer>();
   for( Integer i : input) {
      if(i != 1) rtn.push(i);
   }
   return rtn;
} 

Now lets say I want to filter out 1 and 2

public static List<Integer> filter(List<Integer> input) {
   List<Integer> rtn = new ArrayList<Integer>();
   for( Integer i : input) {
      if(i != 1 && i != 2) rtn.push(i);
   }
   return rtn;
} 

Now lets say 3 and 5s ... this logic is exactly the same except for the predicate check. So we will create an interface

interface FilterNumber {
    public boolean test(Integer i);
}

class Filter1s implements FilterNumber {
    public Filter1s(){};
    public boolean test(Integer i) { return i != 1; }
} 


public static List<Integer> filter(List<Integer> input, FilterNumber filterNumber) {
   List<Integer> rtn = new ArrayList<Integer>();
   for( Integer i : input) {
      if(filterNumber.test(i)) rtn.push(i);
   }
   return rtn;
} 

filter(list, new Filter1s());

As you can see with combinations this becomes tedious too. It would be easier to just allow the user of the api to define the logic they want to preform and if it is only needed once just use an anonymous class

filter(list, new FilterNumber() {
    @Override
    public boolean test(Integer i) {
        return i != 1 && i != 3 && i != 7; 
    }
});

And extending to Lambdas, wouldn't it be even easier to take out all the bloat around i != 1

list.stream().filter( i -> i != 1 )
Scott
  • 1,549
  • 10
  • 17
1

To answer a later comment, "when I write a new subclass, it inherits those private instance variables. In the case of the anonymous inner class, it didn't."

Subclasses never "inherit" private fields of the superclass (using the JLS terminology). However, subclasses may be able to refer to those private fields anyway, depending on where they're located. If the subclass is declared inside the superclass, or if they're both nested inside the same top-level class, the methods of the subclass can still access the field; assuming you have a source file C.java with just one class C, private fields declared somewhere in C.java are still accessible from most other places in C.java.

However, when testing this, I found some interesting nuances:

class Foo1 {    
    private int bar1;
    public static class Foo2 extends Foo1 {
        public void p() {
            System.out.println(bar1);               // illegal
            System.out.println(((Foo1)this).bar1);  // works
        }
    }
}

bar1 is visible, even though it's a private field in the superclass; it's not inherited, but you can access it by telling the compiler to look at the Foo2 object as a Foo1. But just referring to bar1 by itself fails; Java interprets this as an attempt to get the bar1 of the enclosing instance (not the superclass), but Foo2 is static, so there is no enclosing instance.

Note that if Foo2 were declared outside Foo1, the second println would be illegal, because now bar1 is not visible at all, since it's private. The moral here is that "inheritance" and "visibility" (or "access") aren't the same thing. The same thing applies to anonymous inner classes. If you use one in a place where the private instance field is visible, then you can refer to the field; if you use it in a place where the private instance field is not visible, then you can't. The location of the class declaration is more important than the type of class (nested/inner/anonymous) for this purpose.

Suppose we take away the static keyword and make it an inner class:

public class Foo1 {

    private int bar1;

    public Foo1(int x) {
        bar1 = x;
    }

    public class Foo2 extends Foo1 {

        public Foo2(int x) {
            super(x * 10);
        }

        public void show() {
            System.out.println("bar1 = " + bar1);
            System.out.println("((Foo1)this).bar1 = " + ((Foo1)this).bar1);
            System.out.println("Foo1.this.bar1 = " + Foo1.this.bar1);
        }
    }
}

public class Test64 {

    public static void main(String[] args) {
        Foo1 f1 = new Foo1(5);
        Foo1.Foo2 f2 = f1.new Foo2(6);
        f2.show();
    }

}    

Now a Foo2 object is also a Foo1; but since it's an inner class, a Foo2 instance also has an enclosing instance that is a different Foo1 object. When we create our Foo2, it users a superclass constructor to set the superclass bar1 to 60. However, it also has an enclosing instance whose bar1 is 5. show() displays this output:

bar1 = 5
((Foo1)this).bar1 = 60
Foo1.this.bar1 = 5

So just bar1 by itself refers to the field in the enclosing instance.

ajb
  • 29,914
  • 3
  • 49
  • 73