Java Generics - how to access subclass parameters - java

My sample code structure is like this. There is one parent class Building and one subclass House.
Buiding
public class Building {
private String name;
private int noOfHouses;
}
House
public class House extends Building {
private String houseNumber;
}
I want to write a generic method so that i can access the subclass method also.
something like this.
public <T> void construct(T a){
System.out.println(a.getHouseNumber());
}
Please help.

In fact your example does not show the need of generics. You can use:
public static void construct(House a){
System.out.println(a.getHouseNumber());
}
The same thing, unnecessarily complicated to use generics would also work fine:
public static <T extends House> void construct(T a){
System.out.println(a.getHouseNumber());
}

You can't, and shouldn't do that. It's a bad idea to make parent classes aware of child classes' own concrete methods.
You can use a bounded parameter, if this method is in House, or any other class that doesn't complicate the parent/child relationship:
public static <T extends House> void construct(T a){
System.out.println(a.getHouseNumber());
}
The same thing can be done if the parent is abstract, as suggested above:
public abstract class Building {
private String name;
private int noOfHouses;
public abstract String getHouseNumber();
public static <T extends Building> void construct(T a){
System.out.println(a.getHouseNumber());
}
}
Note that the parent doesn't have to be abstract, as long as it's OK with your design

Generics have nothing to do with this problem. Java provides you with the facility of RunTimePolymorphism, but you can't invoke child's specific method using parent reference.
Consider the following case:
Building b = new House(); //Fine
b.getHouseNumber() // Compiler will be happy only if getHouseNumber is in Building.

I agree with Ernest Kiwele, but if you want to access a method that will be part of a subclass you can override a method in each subclass
abstract class Building{
private String name;
private int noOfHouses;
public abstract String getHouseNumber();
public void construct(){
System.out.println( getHouseNumber() );
}
}
public class House extends Building{
private String houseNumber = "houseNumber";
public String getHouseNumber(){
return this.houseNumber;
}
public static void main(String[] args){
House h = new House();
h.construct();
}
}

Related

Is it possible to extend a parametrized class to another parametrized class with one parameter inheriting from the first one?

I'm fairly new to Java so I don't know if this is a bad practice or even possible, but let's get to it.
I'm trying to understand the working of inheritance in a map. Let's say I have these three classes:
public abstract class Person{
private String ssNumber;
public void genericPersonMethod(){/*do thing*/}
}
public class Patient extends Person{
private String patientID;
public void specificPatientMethod(){/*do thing*/}
}
public class Medic extends Person{
private String medicID;
public void specificMedicMethod(){/*do thing*/}
}
}
And then I try to build some kind of crude database for each extended class. I've tried doing this:
public abstract class PersonDB extends HashMap<String, Person>{
private RandomObject personDBGenericProperty;
public void genericThingToDoWithAPersonDB(){}
}
public class PatientDB extends PersonDB{
private RandomObject patientDBSpecificProperty;
public void specificThingToDoWithaPatientDB(){}
}
But then I've found out it doesn't work and it can't extend PersonDB to another class effectively. If I just make some PatientDB extends PersonDB and MedicDB extends PersonDB, the problem is that I could theoretically insert both Patients and Medics, and I couldn't access either classes' specific methods because they're both considered Persons. Doing PatientList<String, Patient> extends PersonDB is even worse because it then accepts any kind of Object. I'm honestly lost about what to do next.
Also, even if this ends up being bad practice for whatever reason (in which case I'm willing to learn any available workaround), I'd still like to know if there's a way to do this in this specific manner, just out of curiosity.
The best approach would probably be to parameterize the class of person in the map:
public abstract class PersonDB<P extends Person> extends HashMap<String, P> {
private RandomObject personDBGenericProperty;
public void genericThingToDoWithAPersonDB(){}
}
public class PatientDB extends PersonDB<Patient> {
private RandomObject patientDBSpecificProperty;
public void specificThingToDoWithAPatientDB(){}
}

Java visible interface that can not be implemented

I'm working on making a programming language that compiles to JVM bytecode, and it highly relies on interfaces as types. I need some way to make an interface private, but have other code still be able to access it, but not make something that implements it.
I was thinking about using abstract classes with a private constructor, so only the classes in the same file would be able to access it. The only problem is that it is impossible to extend multiple abstract classes at once. For example, the structure of a simple compiled program would be this:
// -> Main.java
public class Main {
public static MyInteger getMyInteger() {
return new MyIntegerImpl(10);
}
public static void main(String[] args) {}
private interface MyInteger {
public int getValue();
}
private static class MyIntegerImpl implements MyInteger {
private final int value;
public int getValue() {
return value;
}
public MyIntegerImpl(int value) {
this.value = value;
}
}
}
And another file, in which there is a problem:
// -> OtherFile.java
public class OtherFile {
public static void main(String[] args) {
Main.MyInteger myInteger = Main.getMyInteger(); //Error: The type Main.MyInteger is not visible.
System.out.println(myInteger.getValue());
}
//I do not want this to be allowed
public static class sneakyInteger implements Main.MyInteger { //Error(Which is good)
public int getValue() {
System.out.println("Person accessed value");
return 10;
}
}
}
The reason why I want to do this is so one person can not mess up any other person's code by providing their own implementations of things that should be only implemented by that other person.
Any help would be much appreciated.
I'm pretty sure that you should think again about what you are trying to do and change approach, but the answer for your question is to add to the interface some empty void method that is getting the parameter of the inner private class specific for the wrapper class
public class Test {
private class InnerPrivateClass {
private InnerPrivateClass() {}
}
public interface MyInteger {
int getValue();
void accept(InnerPrivateClass c);
}
private class MyIntegerImpl implements MyInteger {
#Override
public int getValue() {
return 0;
}
#Override
public void accept(InnerPrivateClass c) {}
}
}
However, as I said, I don't like this and for me it means that your idea is broken

when you extend a private class. are the public and protected members of class become private

when you extend a private class. Are the public and protected members of class become private. if not any explanation.
if you extend a nested private class, it wont change public/protected modifiers of the members. Here is an example :
public class Clazz {
private static class NestedClazz {
public int value = 123;
}
public static class NestedClazzExt extends NestedClazz {
}
}
you can now access the inherited member: value from outside
public static void main(String[] args) {
NestedClazzExt nestedClazz = new Clazz.NestedClazzExt();
System.out.println(nestedClazz.value);
}
you can create private class in side a class . We call it as Nested classe. Means a class inside a class. The Concept itself is saying that you can create private class in side another class. The private class will act like as data member to the outer class.
So, You can't extend the private class.
Based on your query I tried to prepare a simple class.
public class pvtClass {
private class As {
public String abc = "private attribute";
public void print(){
System.out.println("privateClass");
}
}
class Ab extends As{
public String ab = "extended attribute";
public void printAb(){
System.out.println("extended class");
print();
System.out.println(abc);
}
}
public static void main(String as[]){
Ab ab1 = (new pvtClass()).new Ab();
As as1 = (new pvtClass()).new As();
ab1.printAb();
as1.print();
System.out.println(as1.abc);
}
}
If you have a look at this class, I have a private class named "As" which has public attribute and public methods. I have another class named "Ab" which extends "As". I have written a main method to invoke the private attribute and methods.
below is the output for the code snippet:
extended class
privateClass
private attribute
privateClass
private attribute
There is a difference between the access of the members of a class and the access to the type itself.
public class C {
private class InnerP1 {
public void m() {
System.out.println("InnerP1.m()");
}
}
private class InnerP2 extends InnerP1 {
public void p() {
this.m();
System.out.println("InnerP2.p()");
}
}
public InnerP1 strange() {
return new InnerP2();
}
}
In this example, the interface I is visible from outside class C. The classes InnerP1 and InnerP2 are not visible from outside C. Jave itself makes not restrictions to the visibility of types you use in your public interface. The method strange() of class C returns a result of class InnerP1. Since outside of C we do not know anything about the class InnerP1 other than it is subtype of Object, the only thing we can do is use the result of strange() as an Object.
public class D {
public static void main(String[] args) {
C c = new C();
Object o = c.strange();
if(o.equals(c.strange())) {
System.out.println("Strange things are going on here!");
}
}
}
As #KnusperPudding pointed out already, the visiblity of public members is not changed, we might just not have enough knowledge of the type itself to access them.
Access to members cannot be restricted by sub-classing. When you mark a class as private then access via the class name is restricted i.e. to the same .java file, however once you have an instance of this class it can be accessed at least as easily as the super class.

Java abstract class constructor and new keyword

I am a junior developer and I am familiar with the theory behind java abstract classes and how they can have constructors to force subclasses to set certain constructor parameters, and how abstract classes themselves cannot be instantiated. However, when looking at some refactored code in my company's test framework I am slightly puzzled.
This abstract class
public abstract class WaitForTestOutcomeThenAssert {
private long maxWait;
public WaitForTestOutcomeThenAssert(long maxWait) {
this.maxWait = maxWait;
}
public void waitForConditionThenAssert() {
...
...
}
protected abstract boolean checkCondition();
}
gets referenced in this class:
public class DbWrapper extends AbstractDB {
#Override
public void assertColumnValueNotNull(final String schema, final String table, final String columnName, final String whereClause) {
new WaitForTestOutcomeThenAssert(this.assertionTemporalTolerance) {
#Override
public boolean checkCondition() {
return getColumnValue(schema, table, columnName, whereClause) != null;
}
}.waitForConditionThenAssert();
}
}
Since we can't instantiate an abstract class, can someone please explain to me exactly what happens and what gets created when we use new keyword in front of an abstract class constructor?
Try looking at anonymous classes. Here you have an anonymous class declaration that extends abstract class WaitForTestOutcomeThenAssert and overrides checkCondition method.
This is not an abstract class
new WaitForTestOutcomeThenAssert(this.assertionTemporalTolerance) {
#Override
public boolean checkCondition() {
return getColumnValue(schema, table, columnName, whereClause) != null;
}
}
That is an anonymous class that extends WaitForTestOutcomeThenAssert. In other words, by writing that you are subclassing "WaitForTestOutcomeThenAssert" and instantiating it.
This is an Anonymous class. It's a shortcut to use Abstract class or Interface without having to explicitly write a subclass.

Super class which uses the values from children

I wanted to implement a method in a abstract class that is called by the inherited classes and uses their values.
For instance:
abstract class MyClass{
String value = "myClass";
void foo(){System.out.println(this.value);}
}
public class childClass{
String value="childClass";
void foo(){super.foo();}
}
public static void main(String[] args){
new childClass.foo();
}
This will output "myClass" but what I really want is to output "childClass". This is so I can implement a "general" method in a class that when extended by other classes it will use the values from those classes.
I could pass the values as function arguments but I wanted to know if it would be possible to implement the "architecture" I've described.
A super method called by the inherited class which uses the values from the caller not itself, this without passing the values by arguments.
You could do something like this:
abstract class MyClass {
protected String myValue() {
return "MyClass";
}
final void foo() {
System.out.println(myValue());
}
}
public class ChildClass extends MyClass {
#Override
protected String myValue() {
return "ChildClass";
}
}
and so on
This is a place where composition is better than inheritance
public class Doer{
private Doee doee;
public Doer(Doee doee){
this.doee = doee;
}
public void foo(){
System.out.println(doee.value);
}
}
public abstract class Doee{
public String value="myClass"
}
public ChildDoee extends Doee{
public String= "childClass"
}
...
//Excerpt from factory
new Doer(new ChildDoee);
I believe you are asking whether this is possible:
public class MyClass {
void foo() {
if (this instanceof childClass) // do stuff for childClass
else if (this intanceof anotherChildClass) // do stuff for that one
}
}
So the answer is "yes, it's doable", but very much advised against as it a) tries to reimplement polymorphism instead of using it and b) violates the separation between abstract and concrete classes.
You simply want value in MyClass to be different for an instance of childClass.
To do this, change the value in the childClass constructor:
public class childClass {
public childClass() {
value = "childClass";
}
}
Edited:
If you can't override/replace the constructor(s), add an instance block (which gets executed after the constructor, even an undeclared "default" constructor):
public class childClass {
{
value = "childClass";
}
}

Categories