Creating Inner Classes and using them (understanding some code) - java

I have been reading through some documentation on inner classes, and am currently reading my textbook, where I have found some good knowledge on using Inner classes. For starters I would like to consider the following example and just make sure I am understand things correctly. For reference I have read the follwing Inner Classes Documentation and have read a couple of SO questions. Hopefully someone can guide me through the following.
import java.util.ArrayList;
public class Gearbox {
private ArrayList<Gear> gears;
private int maxGears;
private int currentGear;
public Gearbox(int maxGears)
{
this.maxGears = maxGears;
this.gears = new ArrayList<Gear>();
Gear neutral = new Gear(0,0.0);
this.gears.add(neutral);
}
public class Gear
{
private int gearNumber;
private double ratio;
public Gear(int gearNumber,double ratio)
{
this.gearNumber = gearNumber;
this.ratio = ratio;
}
public double driveSpeed(int revs){
return revs * ratio;
}
}
}
In the main.java
public class Main {
public static void main(String [] args)
{
Gearbox ford = new Gearbox(6);
Gearbox.Gear first = ford.new Gear(1,20);
System.out.println(first.driveSpeed(10));
}
}
What I am kind of confused about is the notation to actually use some stuff from the nested class. For example
Gearbox ford = new Gearbox(6);
Here we make a ford object belonging to the class of Gearbox, which passes in a value of 6 to maxGears.
Next we have Gearbox.Gear first = ford.new Gear(1,20);, Here is where I am kind of confused on what is really going on. Does the .Gear let the compiler know that Gear is an inner class within Gearbox? If so, why is the next statement ford.new Gear(1,12.3)?
Wouldn't something like Gearbox.Gear first = new ford.Gear(1,12.3); make more sense?

Next we have
Gearbox.Gear first = ford.new Gear(1,20);
Here is where I am kind of confused on what is really going on. Does the .Gear let the compiler know that Gear is an inner class within Gearbox?
Yes ... sort of. Actually, it is saying "I am talking about the Gear class that is declared in Gearbox. It is not necessarily an inner class: it could be a nested class.
If so, why is the next statement ford.new Gear(1,12.3) ?
An instance of an inner class must be created in the context of an instance of its enclosing outer class. The ford.new Gear(...) is saying create the new Gear instance in the context of the Gearbox instance that ford refers to.
(If that still doesn't make sense, reread the above paying special attention to usage of the the word "instance". An instance of a class is an object .....)
As #Thilo points out, making Gear an inner class (rather than a nested class) here does not really achieve anything. It would probably be better to a redeclare Gear as
public static class Gear ...
and then you would not need to qualify the new with an instance of the Gearbox class.

Your inner class is not static, which means it belongs to a concrete instance.
Gearbox.Gear first = new ford.Gear(1,12.3);
Means that you create a Gear for instance ford.
Here you can read some more about inner class and about difference of static and non-static inner classes.

Related

Why can't we access or re-assign a value to an OuterClass instance field from within InnerClass, outside its method/block?

I am preparing for Java 11 certification and while revising Java concepts, I got trapped in one of the silly concept.
I know that OuterClass's instance fields could be accessed from an InnerClass using OuterClass.this.
Please help me to understand why we cannot re-assign a value to OuterClass's instance fields inside an InnerClass (outside a method or block).
public class OuterClass {
String outerInstanceField = "Outer instance field"; // Instance Field
class InnerClass {
OuterClass.this.outerInstanceField = "Inside Inner Class, now";
}
}
Above code throws error:
However, this works perfectly fine if the re-assignment is done either in a block or in the InnerClass method.
public class OuterClass {
String outerInstanceField = "Outer instance field"; // Instance Field
class InnerClass {
{
OuterClass.this.outerInstanceField = "Inside Inner Class, now";
System.out.println(OuterClass.this.outerInstanceField);
}
void print(){
OuterClass.this.outerInstanceField = "Inside Inner Class's method, now";
System.out.println(OuterClass.this.outerInstanceField);
}
}
public static void main(String[] args) {
OuterClass outerObject = new OuterClass();
InnerClass innerObject = outerObject.new InnerClass();
innerObject.print();
}
}
Output:
Nested Class class example
class OuterClass {
static String outerInstanceField = "Outer instance field"; // Static/Class Field
static class InnerClass {
OuterClass.outerInstanceField = "Inside nested Class, now"; // Compiler error
static {
OuterClass.outerInstanceField = "Inside nested Class's static block, now"; // works fine
System.out.println(OuterClass.outerInstanceField);
}
}
}
I might be wrong here, but where you first have this assignment is a completely non-dynamic (for lack of better word and because I don't want to use the in this context ambiguous word 'static') area. There you would define things about the current scope, like which fields this class has or which methods.
That's why the assignment to String outerInstanceField works, as you are in the Scope of the OuterClass and are defining how it is defined.
What you are doing in the Innerclass is actually dynamic, i.e. something that would be executed. But you cannot even tell, when. Is it at the time of class loading? When some object is created? You have no information about that.
You also cannot put for example an if or a loop there, which basically is the same.
In this second snippet you could for example also try to add a static before the block. This will also not work, because it will be executed when the class is loaded and then you cannot even have an instance of OuterClass.
Edit, as response to your comment: It would be nice if you added a small example of what you mean, so I can be sure but if I understand correctly, the problem is the following: The InnerClass in your example is not static. This means, it will always belong to exactly one instance of OuterClass. This is, why OuterClass.this is unambiguous and works. On the other hand, there can be an arbitrary number of InnerClass-Objects for one OuterClass Instance, i.e. InnerClass.this can not be determined uniquely and therefore does not work.
Considering below scenario:
public class A{
int x = 10;
}
class B extends A{
x = 0;
int y = x;
}
If we execute above code, we receive compiler error:
We cannot have isolated expressions outside the scope of a constructor, a method, or an instance/static initialization block.
So, the questions narrows down to whether variable assignment is an expression or statement.
In The Java™ Tutorials, under topic Expressions, Statements, and Blocks it is mentioned that assignment and declaration are statements.
Also,
Learning Java, by Patrick Niemeyer, Daniel Leuck
mentions,
Technically, because variable assignments can be used as values for further assignments or operations (in somewhat questionable programming style), they can be considered to be both statements and expressions.
So, I am considering it as special case of expression.

Referencing inner class instances from the outer class

I've just started working through the Java tutorials again and I decided to spend some time playing with nested classes.
The working copy I've made is a Bicycle class which could have zero or more Rider class instances within it. From within an instance of Bicycle, I'd like to be able to work with instances of Riders.
In the example below, my Bicycle has an ArrayList which holds its Riders, but I'd like to avoid having to maintain this list if possible.
My question is this. Is there another way to reference instances of Rider from Bicycle, or do I have to maintain my own list?
//Outer Class contains zero or more Inner Classes
public class Bicycle {
//ArrayList of Inner Class instances
private List<Rider> Riders = new ArrayList<Rider>();
class Rider {
private String riderName;
protected Rider(String newRiderName) {
this.riderName = newRiderName;
}
protected String GetRiderName(){
return riderName;
}
}
//When creating an Outer Class, we can instantiate zero or more Inner Classes, by name
public Bicycle(String... startingRiderName) {
//Loop through all Inner Class instance names and create an Inner Class for each
for (String newRiderName : startingRiderName) {
Riders.add(new Rider(newRiderName));
}
}
//Public method to return an array of Inner Class instance names
public String[] GetRiderNames() {
String[] riderNames = new String[Riders.size()];
// Just in case we mess up and ask the ArrayList for an out of bounds index
try {
for (int riderIndex = 0; riderIndex < Riders.size(); riderIndex++) {
riderNames[riderIndex] = Riders.get(riderIndex).GetRiderName();
}
return riderNames;
} catch (IndexOutOfBoundsException e) {
return null;
}
}
}
A list has to be maintained somewhere, otherwise those inner class instances will be garbage-collected. Whether that's in an array that is a member of Bicycle or in some external data structure is a design decision, but there's no automatic list kept by Java of inner class instances.
Yes you will need to maintain a list.
Also, a Rider doesn't seem like it should be an inner class of Bicycle. By making Rider an private inner class you are saying that it is only ever useful to Bicycle. Conceptually an inner class is more for some sub-part of Bicycle that performs an internal operation on or holds internal data that composes and is specific to that bicycle. I could imagine a FlatTyreEventHandler being an inner class, but I don't think of the Rider as part of the internal fabric or operation of a Bicycle.
Now, having a Rider and internal class of Bicycle might work in your instance, but bear in mind that anything the outside world wants to know about a rider will have to go through Bicycle, so you will have to keep adding methods such as GetRiderAge(), GetRiderRoutePreference(). These methods are specific to a rider and have nothing to do with a Bicycle. If you find yourself doing this, then Rider is not really an internal hidden class, but instead the methods on Bicycle are just passthroughs to Rider methods and having it as an internal class serves little purpose. Also, the Bicycle has lost its single purpose (of being a Bicycle) and is bloated out with a Rider interface.
So, I would probably make Rider a stand-alone class and then Bicycle has a list of Riders. Alternatively, you can have a separate class which is BicycleRiders and this class can hold a map from bicycles to riders.

Is there any way to use a non-static method in a static class?

I'm trying to implement a simple spreadsheet using Java. It interacts with the user through some menus on the console, and a user can import a given file with some pre-made info about the spreadsheet to be created (lines, columns, and content of cells).
I am trying to make a static class which I called Parser, and the goal of this class is to break down each line of the import into little pieces so I can then apply the correct methods to them (read the cell to which content is being added, and what type of content am I trying to add).
I made my Parser static, because I want to use it without the need of instantiating a new object every time I need it (is this correct?). I have a specific method that is giving me trouble though. Whenever I receive input like this: 1;1|=2;3it means that my cell 1;1 references the cell 2;3. I am telling the parser to return a new Reference(getCell(i,j)). This is because my Reference class constructor receives a Cell, but of course the java compiler tells me I cannot use a non-static method, which is the case of the getCell, inside that static class.
So my question is: is there any way to overcome this problem? Any way to use a non-static method in a static class or should I instantiate a new Parser object when I try to read an import file?
It might be helpful to see some of your code to determine which method is more appropriate, but as this is a common pitfall in object oriented design, I'll try to answer the question generically.
If you define something as static, that means it has no association with any instances, even though it shares the class name. For instance,
public class Table {
List<Cell> cells;
public Table() {
while (someCondition)
parseInput(nextInput);
}
public Cell getCell(int i, int j) {
...
}
public static Cell parseInput(String input) {
Cell cellToReturn = new Cell();
...
if (input.references(cell)) cell = getCell(i,j); //Error here!
...
return cellToReturn;
}
}
The problem arises because the parseInput method is static, and yet it is referencing a specific instance's list of cells! Which one is it referencing? Who knows!
You can solve the issue two ways:
1: Make the parser non-static: public Cell parseInput(String input) {
2: Pass the table to the parser, so it knows what to reference:
public static Cell parseInput(String input, Table target) {
Cell cellToReturn = new Cell();
...
if (input.references(cell)) cell = target.getCell(i,j); //No more error!
...
return cellToReturn;
}
Now, as you stated, the parser is a class, not just a method. But the general rule still applies. You cannot reference an instance field from a static method, because that static method is not associated with any instance!
I made my Parser static, because I want to use it without the need of instantiating a new object every time I need it (is this correct?).
Maybe, but not for the reason you state. Why don't you want to create an instance of your class? If that's your only reason for making it static, then it's not a very relevant one. Indeed, something like the Singleton Pattern essentially achieves the same thing, ensuring that you don't have to keep creating an instance, because there's always exactly one instance to use.
If your object is exactly that... an object, then it should probably be modeled as an instance. I generally tend to think of things which are objects as non-static by nature and things which are concepts about an object are more static by nature.
Let's use the belabored OO example of cars for a moment. If I want to know the price of a car, that's a property of a particular car. I'd have to specify an instance of an Accord for example in order to query it for that property. If, on the other hand, I want to know the average price for a particular model, that's more of a static concept. I'm not talking about any particular instance of Accord, just Accords in general. So where something like getPrice() would be an instance method on Car, something like getAveragePrice() might not.
should I instantiate a new Parser object when I try to read an import file?
Is that such a bad thing?
Now, for the problem at hand, which reference specifically is the compiler complaining about? I guess I'm having trouble picturing it, can you provide a simplified code example so I can see how these static and non-static classes/members relate? Essentially you can reference instance members from a static location, you just need to reference an instance in order to do it. Taking my belabored example above, I can't do this:
class Car {
int getPrice() {
return 20000;
}
static int getAveragePrice() {
return Car.getPrice();
}
}
But I can do this (albeit probably ill-advised in this overly-contrived example):
class Car {
int getPrice() {
return 20000;
}
static int getAveragePrice() {
var someRandomCar = new Car();
return someRandomCar.getPrice();
}
}
If your static method need access to non-static methods (without instantiating anything or accessing instance directly), then MUST be defined as non-static.
private static Parser INSTANCE = new Parser();
public static Parser getInstance() {
return INSTANCE;
}
...
public void nonStaticMethod() {
Parser parser = Parser.getInstance();
parser.whateverParserMethodYouWant();
}
Editing to make this more clear:
class Parser {
private Parser() {}
private static Parser INSTANCE = new Parser();
public static Parser getInstance() {
return INSTANCE;
}
}
...
class ParserClient {
...
public void nonStaticMethod() {
Parser parser = Parser.getInstance();
parser.whateverParserMethodYouWant();
}
}

How to use a private method in Java

I am given a class that has a private method say setCoors(int x, int y). The constructor of that class has the setCoors in it too. In a different class, I want to have a method setLocation which calls setCoors. Is this possible?
New Question:
If I am not allowed to set the method to public, is this possible?
public class Coordinate{
public Coordinate(int a, int b){
setCoors(a,b)
}
private void setCoords(int x, int y)
}
public class Location{
private Coordinate loc;
public void setLocation(int a, int b)
loc = new Coordinate(a,b)
}
The best and most helpful answer depends on the context of the question, which is, I believe, not completely obvious.
If the question was a novice question about the intended meaning of private, then the answer "no" is completely appropriate. That is:
private members of A are accessible only within class A
package-private members of A are accessible only within classes in A's package
protected members of A are accessible only within classes in A's package and subclasses of A
public members of A are accessible anywhere A is visible.
Now, if, and okay maybe this is a stretch (thank you Brian :) ), that the question came from a more "advanced" context where one is looking at the question of "I know private means private but is there a language loophole", then, well, there is such a loophole. It goes like this:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
class C {
private int x = 10;
private void hello() {System.out.println("Well hello there");}
}
public class PrivateAccessDemo {
public static void main(String[] args) throws Exception {
C c = new C();
List<Field> fields = Arrays.asList(C.class.getDeclaredFields());
for (Field f: fields) {
f.setAccessible(true);
System.out.println(f.getName() + " = " + f.get(c));
}
List<Method> methods = Arrays.asList(C.class.getDeclaredMethods());
for (Method m: methods) {
m.setAccessible(true);
m.invoke(c);
}
}
}
Output:
x = 10
Well hello there
Of course, this really isn't something that application programmers would ever do. But the fact that such a thing can be done is worthwhile to know, and not something that should be ignored. IMHO anyway.
No, private means the method can only be called inside of the Class in which it is defined. You will probably want to have setLocation create a new instance of the class setCoords resides in, or change the visibility on setCoords.
EDIT: The code you have posted will work. Just be aware that any instance of the Location class will be bound to its own Coordinate object. If you create a new Coordinate object somewhere else in your code, you will be unable to modify its internal state. In other words, the line
Coordinate myCoord = new Coordinate(4, 5);
will create the object myCoord which will forever have the coordinates 4 and 5.
private means it's private
If you want other classes to call it, maybe you shouldn't make it private?
No private methods can't be accessed outside the class in which they are defined
Kid-doing-homework: the answer is no. Guy-requiring-some-crazy-work-around-for-his-job: the answer is yes. Far more importantly though, Your setCoors method should not take int arguments. It should take two SilverBullet objects.
private means you can only access it inside the class defined.

Why am I able to call private method?

I should not be able to invoke a private method of an instantiated object. I wonder why the code below works.
public class SimpleApp2 {
/**
* #param args
*/
private int var1;
public static void main(String[] args) {
SimpleApp2 s = new SimpleApp2();
s.method1(); // interesting?!
}
private void method1() {
System.out.println("this is method1");
this.method2(); // this is ok
SimpleApp2 s2 = new SimpleApp2();
s2.method2(); // interesting?!
System.out.println(s2.var1); // interesting?!
}
private void method2() {
this.var1 = 10;
System.out.println("this is method2");
}
}
I understand that a private method is accessible from within the class. But if a method inside a class instantiate an object of that same class, shouldn't the scope rules apply to that instantiated object?
Can static method like main access the non-static member of the class, as given in this example ?
Your main method is a method of SimpleApp, so it can call SimpleApp's private methods.
Just because it's a static method doesn't prevent it behaving like a method for the purposes of public, private etc. private only prevents methods of other classes from accessing SimpleApp's methods.
Because main is also a member of SimpleApp.
See below chart
Access Modifiers
**Same Class Same Package Subclass Other packages**
**public** Y Y Y Y
**protected** Y Y Y N
**no access modifier** Y Y N N
**private** Y N N N
As your method is inside car it's accessible based on above thumb rule.
From the Java Tutorial:
private modifier—the field is accessible only within its own class
The main method is inside the same class as the private method and thus has access to it.
private means "only stuff in this class can mess around with it". It doesn't mean "only this instance can call its methods", which seems to be what you're expecting. Any code in SimpleApp can use anything in any SimpleApp. The alternative would be to break encapsulation -- how would you make a proper equals method, for example, that didn't require access to another instance's fields, without making those fields protected or even public or requiring getters for data that should only be available inside the class?
The call you issue is from within the same class where your private method resides. This is allowed. This is the way 'private' is defined in java.
In the program, we created two instances of the class by using which we called two private methods. It's a kind of interesting to see this works is that this is the way we used to call public or default methods outside its class using object reference. In this case, it's all done inside the class definition, so it's valid. The same code put outside the class will result in error.
Because the private scope limits access to the class defining the method, and your main happens to be in the same class.
private modifier—the field is accessible only within its own class.
See Access Modifiers in the Java Documentation.

Categories

Resources