For a particular program, I essentially have an abstract superclass with several different subclasses. However, I'm having trouble with field shadowing as illustrated below.
abstract class Super {
String name;
String getName() {
return name;
}
}
Now I create subclasses that each have their own "name".
class Sub extends Super {
name = "Subclass";
}
However, creating instances of the subclass, and then calling the inherited method getName() will yield null due to field shadowing.
Is there an easy way to avoid this problem, and to allow subclasses to each have a unique field that can be accessed by an inherited method?
Make the field visible in the child class and initialize it in the subclass constructor or in a subclass instance initializer.
You might try this mechanism (bonus left to reader, extend code to get the name of the class directly). The code use the Abstract classes constructor to set the name. You could also define a setName function in the Super class and use that.
Super class (abstract)
package stackShadow;
public abstract class Super {
String name;
public Super(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Shadow1 class first subclass
package stackShadow;
public class Shadow1 extends Super {
public Shadow1() {
super("Shadow1");
}
}
Shadow2 class second subclass
package stackShadow;
public class Shadow2 extends Super {
public Shadow2() {
super("Shadow2");
}
}
Test class to test getName
package stackShadow;
public class Test {
public static void main(String[] args) {
Shadow1 one = new Shadow1();
Shadow2 two = new Shadow2();
System.out.println("Name for one is: " + one.getName());
System.out.println("Name for two is: " + two.getName());
}
}
Related
Super.java
package x.y.z;
public abstract class Super {
public CustomClass a() {
return new CustomClass();
}
public abstract String getName();
public abstract String getDescription();
}
Sub.java
package x.y.z;
public abstract class Sub extends Super {
public String getDescription() {
return "Is a Sub";
}
}
User.java
package x.y.z;
public class User {
private class UseCase extends Sub {
public String getName() {
return "UseCase";
}
}
public UseCase use() {
return new UseCase();
}
}
In another part of my app I try to access new User().use().a(), and I think this causes the error (it's a compile-time error though).
Trying to compile the above errors:
a() in x.y.z.Super is defined in an inaccessible class or interface
What's causing this error and how do I fix it?
New question
This makes the error disappear for me:
User.java
package x.y.z;
public class User {
private class UseCase extends Sub {
public String getName() {
return "UseCase";
}
}
public Super use() {
return new UseCase();
}
}
Changing the type of User.use() to Super "fixes" the error.
Is this a problematic "fix", or will this work fine without any hiccups?
a() in x.y.z.Super is defined in an inaccessible class or interface
Because a UseCase class, that you are trying to return, is private. Consider the following example, that compiles without errors:
User user = new User();
Sub sub = user.use(); // because of implicit up-casting to Sub (and Sub is public)
sub.a();
If you want to fit these 3 lines into a single expression, you need an explicit cast:
CustomClass custom = ((Sub) new User().use()).a();
Also, as you've already pointed out, you can change the use(...) method return type to a Sub or a Super class, so the following code will work without additional casts:
CustomClass custom = new User().use().a();
The problem here is that the type that you return from User#use (i.e. UseCase) is private to the User class, prohibiting it from being accessed from anywhere outside User. Modifying UseCase to be public instead of private should fix your issue.
public class UseCase extends Sub {
#Override
public String getName() {
return "UseCase";
}
}
public class Solution {
private String name;
Solution(String name) {
this.name = name;
}
private String getName() {
return name;
}
private void sout()
{
new Solution("sout")
{
void printName()
{
System.out.println(getName());
}
}.printName();
}
public static void main(String[] args) {
new Solution("main").sout();
}
}
The method of an anonymous class behaves unexpectedly.
How to make method sout to print "sout", now it prints "main"?
The problem is that String getName() is private.
What this means is that it is inaccessible to methods of derived classes.
However, the anonymous derived class is not only derived, but it is also an inner class. As such, the class has access to private members of the outer class. That is why main gets printed, not sout.
All you need to do to make this work is to make the method non-private: default access, protected, or public would work fine.
Demo.
You would use
System.out.println(super.getName());
You have an anonymous inner class Solution inside a Solution, so getName() implicitly refers to the outer instance because the method is private.
You could also make getName protected instead of private.
The explanation is a bit ornery. getName is visible to the anonymous class because of scope, but since it's private, the anonymous class can't normally refer to getName on itself because it's actually a subclass.
The really strange case of this is when you have a static nested subclass:
class Example {
private void sayHello() {
System.out.println();
}
static class Subclass extends Example {
Subclass() {
// This is a compiler error
// because it tries to call sayHello()
// on an enclosing instance which doesn't
// exist (as if Subclass is an inner class).
sayHello();
}
}
}
I walked through the specification in my answer to a question asking about the static case, which also explains why "main" gets printed here: https://stackoverflow.com/a/28971617/2891664.
public abstract class Human{
public String name;
public int number
public void getInfo(){
Name = JOptionPane.showInputDialog("Please enter your name: ");
money = Double.parseDouble(JOptionPane.showInputDialog("Please enter amount of money .00: "));
}
public void displayInfo(){
JOptionPane.showMessageDialog(null,"Name: "+name+"\n"+
"Number: "+number);
}
}
public class Student extends Human {
}
public class Teacher extends Human{
}
public class Janitor extends Human{
{
I need help if calling the methods getInfo() and displayInfo() in all 3 classes below. I have tried:
public class Student extends Human{
public Student(){
getInfo();
displayInfo();
}
it works, but it generates a warning saying "problematic call in constructor" I guess it is not the best way to do it.
I also tried:
#Override
public void getInfo() {
}
but if I leave it empty nothing happens. Basically I am trying to call the method in the abstract class in a simple way without needing to type it up in every class.
As already mentioned, you shouldn't call overridable methods in constructors, because if another class overrides this method and invokes the constructor of the superclass, it may try to use values that are not initialized yet, since the overriden method will be invoked. Example:
public class Superclass {
protected int id;
protected void foo() {
System.out.println("Foo in superclass");
}
public Superclass() {
foo();
}
}
public class Subclass extends Superclass {
public Subclass(int id) {
super();
this.id = id;
}
#Override
protected void foo() {
System.out.println("Id is " + id);
}
}
This will print the unitialized value of id, since you first call the constructor of the superclass which invokes the foo method of the subclass.
You can fix this by making your methods final if this suits your case.
You get the warning because it's a good practice not to call overridables in the constructor; since these overridables could try to access member variables that are not initialized yet (== null) .
You shouldn't call overridable functions inside a constructor. check this link
This question already has answers here:
Can an abstract class have a constructor?
(22 answers)
Closed 8 years ago.
If you are never going to instantiate an object from that class, when are you going to ever use its constructor? Sorry if I come off as ignorant. I just started a class on Java at my high school.
you can initialize something in parent class , so maybe you need constructor in abstract class.
Because sub classes may use it. For example:
public abstract class Foo {
protected String name;
public Foo(String name) {
this.name = name;
}
}
public class Bar extends Foo {
public Bar(String name) {
super(name); //<-- necessary, otherwise it won't compile
}
public Bar() {
super("default name"); // <-- necessary, otherwise it won't compile
}
}
You have a constructor so subclasses can initialize the state of their parent properly.
public abstract class Parent {
private final String name;
public Parent(String n) { this.name = n; }
public String getName() { return this.name; }
}
public class Child extends Parent {
public Child(String name) { super(name); }
}
There would be no other way to initialize that private final String name attribute in the Parent without a constructor.
Well your parent class or the abstract class stores common variables throught all children classes or subclasses.
This makes it easier to store different objects (with the same parent) into collections such as and ArrayList.
It also allows you to easily manipulate and object without worrying about its details that is contained in the subclass.
You do instantiate the constructor by calling super() within the subclass.
In the following code:
import java.io.*;
public class MyClass1
{
MyClass1()
{
System.out.println("base class");
}
public void print()
{
System.out.println("base print");
}
}
class ChildClass extends MyClass1
{
public ChildClass()
{
System.out.println("child class");
}
public void print()
{
System.out.println("child print");
}
}
Why is it that when I create an instance of type ChildClass the constructor of the base class is also executed??
Because your child class extends the base class - it's an instance of the base class and has all of the same fields and variables, etc. Thus the base class must also be instantiated.
For a concrete example, imagine your base class had the following in:
public class Base
{
final private int id;
public Base()
{
this(-1);
}
public Base(int id)
{
this.id = id;
}
public getId()
{
return id;
}
}
A final variable is guaranteed to be instantiated when the class is constructed. Your child class will have an id field (even if it cannot access it directly with child methods), and since this field is private you cannot possible instantiate it with the child constructor - so a base class constructor must be called.
Bear in mind that this isn't solely an issue with final variables, nor is it unique to any particular features you may use - since your child class is a base class, it needs to be properly instantiated as one.
Because that's what's supposed to happen :-)
Your derived class uses the base class as a foundation. In OO speak it is-a base class. That base class also needs to initialise itself, and consequently its constructor must be called.
It's not obvious from your example, but it will make more sense if you give your base class some (protected) members. Initialise them in the base constructor, and consequently they will have the expected values when viewed from your derived class upon construction.
See below. The field value is visible in the child class. What would you expect as the initialised value ?
public class MyClass1
{
protected int value;
MyClass1()
{
System.out.println("base class");
this.value = 42;
}
}
class ChildClass extends MyClass1
{
public ChildClass()
{
// what would you expect 'value' to be here ?
System.out.println("child class " + value);
}
}
Because compiler by default add super() constructor in the child class constructor if it is not specified . Every Constructor Should have either this() in case of without inheritance or super() method when ever there is an inheritance . To illustrate it i have taken this example .
public class Vehicle {
protected int wheels;
protected int lights;
Vehicle(){
System.out.println("Vehicle Class Constructor");
this.wheels=4;
this.lights=2;
}
}
Vehicle is the parent class
class Car extends Vehicle {
public Car(){
#Compiler add the super() constructor by default
System.out.println("Car class constructor");
}
}
Car is the Child class
public class TestCar {
public static void main(String args[]){
Car c = new Car();
System.out.println("Wheels" + c.wheels);
System.out.println("Lights" + c.lights);
}
}
In above code snippet When i compile the TestCar.java file during the Compile time the compiler looks for the Car constructor and checks whether Car class has any parent as soon as it checks that Car class extends the parent class Vehicle , it checks whether user had provided super() in inheritance tree . if not it adds one .
Hope this helps !