This question already has answers here:
Why can outer Java classes access inner class private members?
(10 answers)
Scope of private variables within inner classes
(4 answers)
Closed 12 days ago.
I've been trying to understand scoping in Java, more precisely, when it comes to having inner classes.
I have the following snipped of code:
import javax.swing.*;
public class OuterClass {
// Constructor
public OuterClass() {
}
public static void main(String[] args) {
OuterClass app = new OuterClass();
app.doStuff();
}
private void doStuff(){
System.out.print("\033[H\033[2J"); // DEBUG clear out output
InnerClass newNote = new InnerClass("images/01-SOL.png");
// QUESTION: why are the following working and accessible??
ImageIcon myIcon = newNote.getIcon();
System.out.println(myIcon.getImage());
System.out.println(newNote.iconPath);
}
// define private inner class
private class InnerClass {
private String iconPath;
private InnerClass(String iconPath){
this.iconPath = iconPath;
}
private ImageIcon getIcon(){
return new ImageIcon(this.iconPath);
}
}
}
I have an Outer class, and within it, an Inner class. As per my question in code, I do not understand WHY the private members of InnerClass (whether properties, or functions) are accessible from OUTSIDE the inner class, meaning in my example, in my outer class.
I'm writing another small swing app, almost done, but am just lost in what scoping I should be using in my Inner classes...
I was expecting to have to
set the inner class itself to private (thus only accessible to the outer class).
set the inner class members to private (thus only the inner class itself could access them)
set the inner class getter/setter functions to public, so that the outer class could access them ...
Doesn't seem to work at all this. I'm puzzled...
Could anyone shed a light on this from my example?
Much much thanks!
==========
UPDATE:
And so we're clear why an inner class... My project is a swing app that shows random music notes. Each note "Note" has a few properties (index, image file, icon, finally, it has an ArrayList of object of type from another inner class "PositionCombi").
The NotePosition class has a positionNum, fingerNum, and stringNum..
Here's the bulk of it:
public class OuterClass {
private String[] allNoteNames = ["C","D","E","F","G","A","B"];
private Note noteImages[];
public OuterClass {
initNotes();
doStuff();
}
private void initNotes(){
this.noteImages = new Note[19];
noteImages[0] = new Note(4, "images/01-SOL.png");
noteImages[0].addPositionCombi(1, 0, 4);
noteImages[0].addPositionCombi(2, 3, 4);
noteImages[0].addPositionCombi(3, 2, 4);
//...etc.
}
private Note getShuffledNote(){
//... return a random note object from this.noteImages
}
private void doStuff() {
// get a suffled note:
Note workingNote = getShuffledNote();
lblNoteName.setText( this.allNoteNames[ workingNote.getIndex ] );
lblImage.setIcon( workingNote.getIcon() );
ArrayList<Note.PositionCombi> notePositions = workingNote.getPositions()
//print positions for given note:
for (Note.PositionCombi notePosCombi : notePosCombinations) {
System.out.println( "Position: " + notePosCombi.getPositionNum() );
System.out.println( "Finger: " + notePosCombi.getFingerNum() );
System.out.println( "String: " + notePosCombi.getStringNum() );
}
}
/*** INNER CLASS DEFS ***********/
private class Note { // inner Note class
private int noteIndex;
private String iconPath;
private ArrayList<PositionCombi> PositionCombis;
private Note(int noteIndex, String iconPath){
this.noteIndex = noteIndex;
this.iconPath = iconPath;
this.PositionCombis = new ArrayList<PositionCombi>();
}
private int getNoteIndex(){
return this.noteIndex;
}
private ImageIcon getIcon(){
return new ImageIcon(this.iconPath);
}
private ArrayList<PositionCombi> getPositionCombis(){
return this.PositionCombis;
}
private void addPositionCombi(int positionNum, int fingerNum, int stringNum){
this.PositionCombis.add(new PositionCombi(positionNum, fingerNum, stringNum));
}
private class PositionCombi { // inner-INNER PositionCombination class
private int positionNum;
private int fingerNum;
private int stringNum;
private PositionCombi(int positionNum, int fingerNum, int stringNum){
this.positionNum = positionNum;
this.fingerNum = fingerNum;
this.stringNum = stringNum;
}
private int getPositionNum(){
return this.positionNum;
}
private int getFingerNum(){
return this.fingerNum;
}
private int getStringNum(){
return this.stringNum;
}
}
}
}
You must understand that the InnerClass and object properties are the same for the OuterClass
Related
I'm new to Java programming, sorry if this is a dumb question.
I find it hard to word this question properly, but I have an assignment to create a aircraft class that can make aircraft land, takeoff etc. And need to test it using Testclass. When the new object are entered it automatically assigns a unique ID to the aircraft in the constructor.
I can do this using a instance method fine as it has a return value which is returned to to Testclass. The question wants me to do this in the constructor itself, however, the constructor never returns anything. So the variable never gets sent to the Testclass. I clearly am not understanding OOP properly. Even when I try to just use a getter method to get the ID created in the constructor it gives me the initialized variable before the the constructor has worked on this. This is the code I have so far and its completely wrong I know but if someone could point me in the right direction or tell me how to word this question better it would be a massive help.
// I need to enter 3 aircraft into the system in the testclass
public class Aircraft {
private int aircraftID;
private static int lastID;
private String airportcode;
private int ID = 100;
private int count;
public Aircraft(int a, int b, int c){
// Constructor
// Assign ID
this.ID = a;
lastID = ID;
ID++;
this.ID =b;
lastID = ID;
ID++;
}
}
OK, you want to create an Aircraft that has an automatically-assigned unique identifier, and can take off and land. That implies you need a field for tracking the identifier, a field for tracking whether it's in the air (or not), and methods for the take off and land operations. You also need a static field for generating the unique identifiers. (Note that this implementation isn't thread safe.)
private class Aircraft {
private static int staticId = 0;
private int uniqueId = 0;
private boolean onGround = true; // Aircraft start on the ground in this implementation
public Aircraft(){
this.uniqueId = staticId; // putting this line first makes uniqueId zero-indexed in effect
staticId++;
}
public void land(){
onGround = true;
}
public void takeoff(){
onGround = false;
}
public boolean isFlying(){
return !onGround; // If it's not on the ground, it's flying
}
public int getUniqueId(){
return uniqueId;
}
}
Unit tests checks all of the methods and expected functionality of the class in question:
import org.junit.Test;
import static org.junit.Assert.*;
import Aircraft;
class Testclass {
private final Aircraft aircraft = new Aircraft();
#Test
public void hasId(){
aircraft.getUniqueId() >= 0;
}
#Test
public void canLand(){
assertTrue(aircraft.land());
}
#Test
public void canTakeOff(){
assertTrue(aircraft.takeOff());
}
#Test
public void checkFlightOperationsAreTrackedCorrectly(){
aircraft.land();
assertFalse(aircraft.isFlying());
aircraft.takeOff();
assertTrue(aircraft.isFlying());
}
}
As pointed out a constructor does not return anything (the simplified version is that with new it returns an object instance). I am kinda guessing at what you are trying to acomplish, but I'll have a go anyways. It seems to me that you are trying to cram the construction of 3 objects into one constructor - which is why your constructor has 3 parameters. Also you are playing havoc with the IDs.
I have removed all the variables that I didnt quite understand, leaving only ID that increments with each instantiated Aircraft. The #Override is mainly just for show.
public class Aircraft {
private int aircraftID;
private static int lastID = 0;
#Override
public String toString(){
return "Aircraft_" + this.aircraftID;
}
public Aircraft() {
lastID++;
this.aircraftID = lastID;
}
}
I took the liberty and wrote the TestClass just to see if we have the same thing in mind. Again the printAircraft() method is for show.
public class TestClass {
private List<Aircraft> aircrafts;
public TestClass(){
aircrafts = new ArrayList<>();
}
public void addAircraft(Aircraft a){
aircrafts.add(a);
}
public void printAircraft(){
Iterator<Aircraft> it = aircrafts.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}
and to test it, we create and instance of TestClass add 3 Aircraft instances and print out the contents
public static void main(String[] args) {
TestClass tc = new TestClass();
tc.addAircraft(new Aircraft());
tc.addAircraft(new Aircraft());
tc.addAircraft(new Aircraft());
tc.printAircraft();
}
This would be the case if you are to write the TestClass. If that is given, it would help to know what it looks like - maybe that would help us understand better.
How can I access private variable inside a class having private constructor.
And how can I change it's value if the variable is declared final from another
class.Have tried few links but not able to get as most of the solutions are having public constructor like:
Link i have tried
Code I have tried:
package com.test.app;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Demo {
static Demo instance = null;
private int checkvalue = 10;
final private int checkvalue1 = 12;
private Demo() {
System.out.println("Inside Private Constructor");
System.out.println(checkvalue);
}
static public Demo getInstance() {
if (instance == null)
instance = new Demo();
return instance;
}
}
class Main {
public static void main(String args[]) {
try {
///this is showing me the value inside the constructor
Class clas = Class.forName("com.test.app.Demo");
Constructor<?> con = clas.getDeclaredConstructor();
con.setAccessible(true);
con.newInstance(null);
///how can i get the value of the private variables inside the class
Field f = Demo.class.getDeclaredField("checkvalue");
f.setAccessible(true);
////throwing me a error
//java.lang.IllegalArgumentException: Can not set int field com.test.app.Demo.checkvalue to java.lang.reflect.Constructor
System.out.println("" + f.get(con));
} catch (Exception e) {
e.printStackTrace();
}
}
}
if you would to change checkValue1 variable, you should to considere to not put this variable as final.
Im trying to add a dog (nyHund) which is created in a different class, to an Arraylist i created using a constructor in another class, but whenever i try to use the Arraylist in the "register" class, im getting the error that the arraylist name can't be resolved.
First class:
public class Hund {
private String namn;
private int ålder;
private double vikt;
private String ras;
public Hund(String hundnamn, int hundålder, String hundras, double hundvikt) {
this.namn = hundnamn;
this.ålder = hundålder;
this.ras = hundras;
this.vikt = hundvikt;
}
public String getNamn() {
return namn;
}
public int getÅlder() {
return ålder;
}
public double getSvanslängd() {
if (ras=="tax"){
return 3.7;
}else{
return ((vikt*ålder)/10);
}
}
public String toString() {
return namn + "\n" + ålder + "\n"+ras+"\n"+vikt+"\n"+getSvanslängd();
}
}
Second Class
import java.util.ArrayList;
public class testning {
public static void main(String[] args) {
Hund nyHund = new Hund("Daisy", 13, "labrador", 22.3);
System.out.println(nyHund.toString());
Register.läggTillHund(nyHund);
}
}
And the Third class:
import java.util.ArrayList;
public class Register {
public static void läggTillHund(Hund nyHund){
hundRegister.add(nyHund);
System.out.println(nyHund);
}
private Register(){
ArrayList<Hund> hundRegister = new ArrayList<Hund>();
}
}
The problem i am experiencing is with "hundRegister.add(nyHund)"
any thoughts? or pointers where im going wrong? (very new at Java)
Best Regards
Oskar
The ArrayList you've created is local to your Register constructor. Declare it inside the class, but outside the constructor, as an instance variable, so it's in scope throughout the class.
public class Register {
private ArrayList<Hund> hundRegister;
private Register(){
hundRegister = new ArrayList<Hund>();
}
}
Additionally, it's unclear why the constructor is private. Nothing else can access that constructor. I would make it public.
Also, in getSvanslängd, replace ras=="tax" with "tax".equals(ras). See How do I compare strings in Java?.
So I have a class LayerCopper that holds a few textboxes and a few methods to set values in those textboxes:
public class LayerCopper extends javax.swing.JPanel {
public LayerCopper() {
initComponents();
}
private static javax.swing.JFormattedTextField CuWeightTextField;
private static javax.swing.JFormattedTextField LayerNumJFormattedTextField;
...
...
...
public void setLayerNumberText(int layerNumber) {
LayerNumJFormattedTextField.setText("" + layerNumber);
}
public void setLayerCuThickness(double CuThickness) {
CuWeightTextField.setValue(CuThickness);
}
}
I also have another class StackupCalculator with multiple instances of the LayerCopper panels in it. I have an arraylist that holds each instance of the LayerCopper panel:
static ArrayList<LayerCopper> layerSet_Copper = new ArrayList<>();
...
...
...
public void createLayerSetArray() {
layerSet_Copper.add(layerCopper1);
layerSet_Copper.add(layerCopper2);
layerSet_Copper.add(layerCopper3);
layerSet_Copper.add(layerCopper4);
layerSet_Copper.add(layerCopper5);
initializeLayerArrayValues();
}
When my initializeLayerArrayValues runs, It's supposed to populate a couple textfields with text:
private void initializeLayerArrayValues() {
for (int i = 0; i < layerSet_Copper.size(); i++) {
layerSet_Copper.get(i).setLayerNumberText(i + 1);
layerSet_Copper.get(i).setLayerCuThickness(0.750);
}
}
When I run the program though it doesn't update the fields. I'm guessing I am calling the main class LayerCopper and not the instanced version of it? How would I call the instanced version of the layer?
According to you, you haven't instantiated LayerCopper. You need to make a new instance of it, and make layerCopper1, layerCopper2, etc. Then use createLayerSetArray().
Like so:
LayerCopper lc = new LayerCopper();
// create values different layerCoppers to go in layerSet_Copper
lc.createLayerSetArray();
I don't quite understand the inner workings of your class, so I could be wrong.
Changing the textfields from static to non-static fixed it for me. /cheers
I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx