I have a java public class I need to modify (only one method). The class is in a package so I'm writing a new class that extends the first class and overriding the method I need to change.
Class A is
public class A {
GL gl;
GLU glu;
PGraphicsOpenGL pgrap;
//other fields
//constructor
public void method() {
this.gl = pgrap.gl;
this.glu = pgrap.glu;
//something else I don't want in class B
}
}
Class B is something like
public class B extends A {
//constructor that recalls super()
public void method() {
super.gl = pgrap.gl;
super.glu = pgrap.glu;
}
}
but I get an error for super.gl = pgrap.gl: The field A.gl is not visible.
I don't have any getter method written in the package, what should I do?
Thanks.
NOTE: I am not able to recompile the package or add the class B to the package.
The default access specifier is package-private which means classes in the same package as A can access this variable using the instances of A
A a = ....
a.gl = ...; // this works.
And package-private members (and private members) are not inherited, only protected and public members are.
Since A#method() is already doing the assignment operation, you call super.method() in B#method() to get your desired behavior. Or you should mark them as protected.
Controlling Access to Members of a Class
A.gl and A.glu are package-private (no explicit modifier). The only way you'd be able to access them is if class B is in the same package as class A.
If they were protected you'd be able to access them as you wish:
The protected modifier specifies that the member can only be accessed
within its own package (as with package-private) and, in addition, by
a subclass of its class in another package.
Fields gl and glu have package access. Use protected access modifiers to make accessible them in sub-classes.
Define variables as protected.
protected int gl;
protected int glu;
Because your variables have default access you will be able to access them in the Same package. So you need to move either B or define them as protected so that they will be accessible to child classes.
Assuming that you can't declare your class B in the same package of class A and you can't directly modifiy class A then only choice is to go by reflection:
public void method() {
Field[] fields = this.getClass().getSuperClass().getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("gl")) {
field.setAccessible(true);
field.set(this, pgrap.gl);
}
}
}
Related
Say I have a class declared with default access. If a member in the class is declared protected or public, is it equivalent to the member being declared with default access?
For example:
In CarA.java:
class CarA { //class declared with default access
public int odometer;
protected void forward(int distance){...
}
protected static void tally(){...
}
}
In CarB.java:
class CarB { //class declared with default access
int odometer;
void forward(int distance){...
}
static void tally(){...
}
}
Are CarA and CarB equivalent?
My reasoning is that since the class is not declared as public, the class is not accessible outside of its package, so its members should not be accessible outside of its package as well. Could someone confirm my thinking is correct?
No, they're not equivalent. Define these in the same package:
public class CarC extends CarA { }
public class CarD extends CarB { }
And in a different package:
import your.package.CarC;
import your.package.CarD;
public class NewClass
{
public static void tryThis(CarC c, CarD d) {
int n1 = c.odometer; // legal
int n2 = d.odometer; // illegal
}
}
No, these would not be equivalent. The odometer would almost be equivalently privileged*, the methods would not be.
This is because what you're calling "default access", also referred to as package-private, means that other members of that package can access the object or method in question. So where you've made odometer public, it would essentially be available to anything with access to the parent class, the protected status of the methods would be available to the package and classes that extend the class in question, even if they are outside of the package, unlike package-private.
*The public odometer in CarA could be accessed by an object or method outside of this package by routing it through a public class that extends this class whereas the package-private odometer in CarB would always be package-private. This is a great reason why one should avoid writing code like that, other developers might assume that the variable is not publicly available.
As far as I know, you can access the members of the class when you can create an instance of the class or when you inherit the class.
A default class can not be accessed outside the package. So I think you can not inherit it as well(outside the package). So I think they are pretty much the same.
You can access the protected members of the class when you can access the class itself(CarA).
Hope I'm right and this gives you some idea.
I am writing small pieces of code to make sure I understand Java basics and I have the following.
package teams1;
public abstract class Team1{
private String sport = new String();
public abstract String getSport();
public abstract void setSport();
}
import teams1.*;
abstract class FootballTeam1 extends Team1{
public String getSport(){
return "Football";
}
public void setSport(){
this.sport="Football";
}
}
It doesn't compile because sport is private in the super class, but I thought FootballTeam1 would inherit it's own copy of sport because it is extending Team1. Any help would be appreciated. Thanks!
You have mostly answered your own question. FootballTeam1 does not have access to the private fields of its parent. That is what the 'protected' scope is used for.
However, the child FootballTeam1 does have its own copy of the field. It has a copy of all fields that the parent class has, which I can see would cause confusion.
The reason for this distinction is modularity. A subclass of a parent class only has access to the parts of the parent class that one has explicitly stated that it may have access to. This allows developers to consider what parts of a class are to be exposed, under the Object Orientated goal known as the 'Open/Closed Principle'; that is, classes should be open for extension, but closed for modification.
The quickest 'fix' to the class is change the scope of the field, for example
private String sport = new String();
becomes
protected String sport = new String();
or
public String sport = new String();
If you do not want to give the child class direct access to the field, but do want to allow it to change the field then a protected setter method could be used. For example, you could add the following to Team1.
protected void setSport( String newValue ) {
this.sport = newValue;
}
Since the class variable sport is private, it is private to the class it was declared in. Extending classes cannot access this variable in the manner you are trying.
Try making the variable protected (which allows extending classes to have visibility on the variable) if you want to continue accessing the sport variable in this manner, otherwise have getters and setters in the abstract class and the extending/implementing classes to call them instead.
Private Methods, Variables and Constructors that are declared private can only be accessed within the declared class itself.
Protected Variables, methods and constructors which are declared protected in a superclass can be accessed only by the subclasses in other package or any class within the package of the protected members' class.
Modified code :
package com.org.abstractc;
public abstract class Team1{
// you have to change this private to protected then it will be inherited
// in child class.
protected String sport = new String();
public abstract String getSport();
public abstract void setSport();
}
Just change private to protected. private means that your subclasses don't have access to variables or methods, whereas protected allows this access.
Private fields are accessible only in the same class. Also, inheritance is mainly used for defining the same name methods in derived classes with seperate functional logic.
I was trying to test working of private interfaces and wrote the code below. I can understand that a situation might arise to declare private interfaces if we don't want any other class to implement them but what about variables? Interface variables are implicitly public static final and hence i was able to access them even if interface was declared private. This can be seen in code below.
public class PrivateInterfaceTest {
/**
* #param args
*/
public static void main(String[] args) {
TestingInterfaceClass test = new TestingInterfaceClass();
TestingInterfaceClass.inner innerTest = test.new inner();
System.out.println(innerTest.i);
}
}
class TestingInterfaceClass {
private interface InnerInterface {
int i = 0;
}
class inner implements InnerInterface {
}
}
Does it mean that we can never really have private interface in true sense? And does it really make sense to if have private interface if we can access variables outside private interface?
EDIT:
Just want to add that same situation will not arise if we have private inner class. A private variable in inner class will never get exposed.
Your member interface is private. The inherited static field is not private.
A private member interface cannot be used as a type outside the enclosing top-level class or enum. This can be useful to prevent external code from implementing an interface you may wish to change. From the JLS:
The access modifiers protected and private pertain only to member interfaces within a directly enclosing class or enum declaration (§8.5.1).
The interface field is public, and inherited by the class that implements the interface. From the JLS:
A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class.
If you want to make the field accessible only within the classes that implement the member interface, you can put its declaration in the enclosing top-level scope.
class TestingInterfaceClass {
private static final int i = 0;
private interface InnerInterface {
// ...
}
class inner implements InnerInterface {
// ...
}
}
As I see, it is not the problem with private interface InnerInterface. It is the inner class which is at default scope inside TestingInterfaceClass exposing the content of InnerInterface. If you don't want the content of InnerInterface to be known to the world, you should also declare all the classes (specifically TestingInterfaceClass) as private.
Because every variable in an interface is public static final, it should be the responsibility of the class (implementing it) whether it should take care of the content inherited from private interface
Even though it's allowed, we don't need (and shouldn't use) an instance to access an static field.
Following is the way to access it -
System.out.println(TestingInterfaceClass.inner.i);
//note you cannot access the InnerInterface like this here because it's private
The inner has inherited the public static field i and i should be visible wherever the inner itself is visible.
Usually, interfaces are used to expose the behaviors of an object, while the implementations are hidden. But in your case, you are attempting the opposite.
The Interface variables are implicitly public static final, but you can't reach this variables because you can't reach previously the interface that contains these variable, which you have declared as private. First you need to be able to see the interface, and after that, go into content of the interface.
Say there's the following base class:
package bg.svetlin.ui.controls;
public abstract class Control {
protected int getHeight() {
//..
}
//...
}
Also, in the same package, there's a class that inherits:
package bg.svetlin.ui.controls;
public abstract class LayoutControl extends Control {
public abstract void addControl(Control control);
//...
}
Then, there's a third class in another package:
package bg.svetlin.ui.controls.screen;
public abstract class Screen extends LayoutControl {
//...
}
And, finally, there's the implementation class, again in a different package:
package bg.svetlin.ui.controls.screen.list;
public class List extends Screen {
private final Vector controls = new Vector();
public void addControl(Control control) {
height += control.getHeight();
controls.addElement(control);
}
}
Even though List inherits from Control, and the getHeight() is protected, there's the following error:
getHeight() has protected access in bg.svetlin.ui.controls.Control
I've checked that my imports are right. I'm using NetBeans.
Any idea what's wrong? I thought protected fields and methods are visible to the children even if the latter are in a different package.
Thanks!
I thought protected fields and methods are
visible to the children even if the latter are in a different package.
That's correct. The class itself has an access to the inherited protected members. But, what you're trying to do it to call the getHeight method on some Control reference. You're allowed to call it only on this instance!
For a better understanding, let me quote Kathy Sierra's SCJP Preparation Guide:
But what does it mean for a subclass-outside-the-package to have
access to a superclass (parent) member? It means the subclass inherits
the member. It does not, however, mean the
subclass-outside-the-package can access the member using a reference
to an instance of the superclass. In other words, protected =
inheritance. The subclass can see the protected member
only through inheritance.
You're right. Any protected member or method accessible from children class, but you want access to protected method of a parameter instance in addControl method. You can access only to protected method of List class (this.getHeight())
I am fairly new to the concept of abstract data types an was looking for clarification because I could not find any good examples online.
From my understanding, the sub class inherits all methods and variables from the abstract but I think I am misunderstanding this. For example, I am creating a menu using the abstract data type MenuItem
import javax.swing.*;
public abstract class MenuItem{
private String itemName;
private int ct;
private double costPer;
public String getItemName()
{
return itemName;
}
public int getCt()
{
return ct;
}
public double getCostPer()
{
return costPer;
}
}
public class Hamburger extends MenuItem{
itemName = "Hamburger";
ct = 0;
costPer = 4.99;
}
I know this is incorrect but can someone tell me why? Does the subclass hamburger only inherit the methods or what?
There are several issues:
itemName et al are private, so even though they're inherited, they're not visible to the subclass.
The syntax you use in Hamburger is invalid.
Here is how you could fix your code:
public abstract class MenuItem{
public MenuItem(String itemName, int ct, double costPer) {
this.itemName = itemName;
this.ct = ct;
this.costPer = costPer;
}
...
}
public class Hamburger extends MenuItem{
public Hamburger() {
super("Hamburger", 0, 4.99)
}
}
Finally, I'd say that instead of using an abstract base class and a bunch of concrete classes, it would be better to use a single concrete class for MenuItem and make Hamburger etc instances of that class.
The problem lies in the visibility of the fields in your MenuItem parent class. private visibility means, that they are not visible to any other class including own subclasses.
In oreder to make your fileds visible to subclasses, you have to change their visibility to protected. Be aware that this makes the fields visible to all classes in the same package as well.
All the memeber visibility issues are covered in greater detail in this article
From my understanding, the sub class inherits all methods and variables from the abstract but I think I am misunderstanding this
yes, your understanding about your mis-understanding is correct. :-)
sub classes in java do not inherit the private member variables. they get public and protected members only.
itemName, costPer and ct are declared as private access fields. They are only accessible from within the class they are defined in. If you declare them with protected access, you'll be able to access them.
As defined in the Java Language Specification, section 6.6 Access Control
A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible and the member or constructor is declared to permit access:
...
(Otherwise,) if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
...
Before you start looking into abstract types, start with the concept of encapsulation, and try to understand it as it is considered (by many) as the most important concept in the object-oriented design, followed by polymorphism, and inheritance. If class members are private, no subclass will be able to access them directly.
Yes, Hamburger only inherits the methods. That's because they're public. If you made them private (like the fields) they wouldn't be inherited either. Here's how to fix the problems.
import javax.swing.*;
public abstract class MenuItem {
//To be visible to subclasses, these need to be public, package-private, or protected
protected String itemName;
protected int ct;
protected double costPer;
public String getItemName() {
return itemName;
}
public int getCt() {
return ct;
}
public double getCostPer() {
return costPer;
}
}
public class Hamburger extends MenuItem {
//These assignments need to be inside a block, like a constructor
public Hamburger() {
itemName = "Hamburger";
ct = 0;
costPer = 4.99;
}
}
An abstract class can never be instantiated. Its sole purpose is to be extended. In an abstract class, if you specify atleast one method as abstract, then the whole class needs to be specified as abstract. An abstract class allows you to have implemented and unimplemented (abstract) methods all in the same class. If all methods in the class are abstract, then you effectively have a interface, and any variables declared in an interface are treated as constants. The variables in your question are not inherited as they are private to the abstract class. You must access them through the methods of the abstract class.