We help IT Professionals succeed at work.

Java: Inner classes - How to have access to inner class variables

Software Software
on
Hello,
I have a class car and an inner class engine. The inner class shouldn't be visible outside of the class car.
Is there still a way to give a Car an Engine as parameter?
Error: Car.Engine has private access in Car
Here is my code:

public class Main {
    public static void main(String[] args) {
        Car car = new Car("VW", "Red", new Car.Engine("Diesel"));
    }
}

Open in new window


public class Car {
    private String brand;
    private String color;
    private Engine engine;


    public Car(String brand, String color, Engine engine){
        this.brand=brand;
        this.color=color;
        this.engine=engine;
    }

    public Engine getEngineType(){
        return new Engine(engine.getType());
    }


    public void setEngine(Engine engine){
        this.engine=engine;
    }

    private class Engine{
        private String type;

        public Engine(String type){
            this.type=type;
        }

        public String getType() {
            return type;
        }
    }
}

Open in new window

Comment
Watch Question

CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
Is there still a way to give a Car an Engine as parameter?
Not normally. You can probably do it with reflection though.

Author

Commented:
So, why to use private inner classes? Have someone a good example?
CERTIFIED EXPERT
Commented:
Inner classes are mostly for 'intimate' implementational purposes where exposure to the enviro outside the enclosing class is not required. (One use I've made of them in the past was for running threads).

-----------------

Not sure if this is a useful interpretation of your code :

import java.util.*;

public class CarS {
    private String brand;
    private String color;
    private Engine engine;

    
    public static void main(String[] args) {
        CarS car = new CarS("VW", "Red",  "Diesel");
        
        System.out.println(car.engine.getType());
        System.out.println(car.getEngineType().getType());
    }
    
    

    public CarS(String brand, String color, String engine){
        this.brand=brand;
        this.color=color;
        this.engine = new Engine("Diesel");/*.engine=engine;*/
    }

    public Engine getEngineType(){
        //return new Engine(engine.getType());
        return this.engine;
    }


    public void setEngine(Engine engine){
        this.engine=engine;
    }

    private class Engine{
        private String type;

        public Engine(String type){
            this.type=type;
        }

        public String getType() {
            return type;
        }
    }
}

Open in new window

CERTIFIED EXPERT

Commented:
Like Krakatoa says, if you want to use a private inner class, it should be entirely used for implementation details within the class.

One way to think about this is, you should be able to delete that inner class and replace it with something else and no code outside of the class should be affected.

You can see that the code you tried to write wouldn't satisfy that, because you're building an Engine outside to pass in.  So that code would need to be changed if you deleted Engine.

So even after the rewrite Krakatoa proposed, the class is still passing Engine instances outside itself (e.g. getEngineType()).

I think a better rewrite would be to have getEngineType () return a String (this.engine.getType()) and then the setEngine method could be renamed to setEngineType(String type) and inside that create a new Engine instance.

I'd write out the code, except I'm using my phone and it would take too long to type :(

Anyway, hope that helps,

Doug
CERTIFIED EXPERT

Commented:
One way to think about this is, you should be able to delete that inner class and replace it with something else and no code outside of the class should be affected.

You can see that the code you tried to write wouldn't satisfy that, because you're building an Engine outside to pass in.  So that code would need to be changed if you deleted Engine.

So even after the rewrite Krakatoa proposed, the class is still passing Engine instances outside itself (e.g. getEngineType()).

I think a better rewrite would be to have getEngineType () return a String (this.engine.getType()) and then the setEngine method could be renamed to setEngineType(String type) and inside that create a new Engine instance.

This is top advice and deserves more of the credit really on this question. In particular the dimension Doug mentions that inner code should be replaceable without any effect on the outside world. Clincher.

If you want to re-allocate your points in this one Software Software, then do. Inc girionis' contribution. My kludge is a workaround that Doug pointed out is just a workaround.

k.