Suppose I have a superclass A and it has fields
class A {
String name;
int age;
setName(String name);
getName();
setAge(int age);
getAge()
}
I have multiple classes that extend A and add more fields along with the getters and setters.
Now there is another class, say B, which requires name and age, which is already provided by class A.
So should I go ahead and create class B without any field and simply it extends class A, or should I directly use class A?
class B extends A {}
P.S - I am using generics, which gives me a warning when I directly use superclass A, but the functionality is working fine. Please suggest.
Mostly the design wont be proper and justified if u just create a Class that do not have its own state, but yes it make sense if
A is abstract class i.e. you want to restrict the users to create an instance of A hence mark it abstract , then by creating B you are creating an implementation of A.
below is the example for the same
abstract class A{
protected String name;
protected int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class B extends A{}
also to make code more dynamic at runtime if u want to just use the parent class fields into ur function then probably u can do this
abstract class A{ // you can altogether remove 'abstract' and not create a B class
protected String name;
protected int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class B extends A{}
class C extends A{
protected String location;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
now see the below method
public static <T extends A> void printName(List<T> list) {
for (T t : list) {
System.out.println(t.getName());
}
}
this qualifies for List<B>, List<C>
There is really no reason, that I can think of, where you need to extend a class without changing anything. Maybe you feel that you will need it in the future. This violates the YAGNI principal.
Just use Class A. You can make changes when they are needed.
It really is pointless. If it gives you a warning, there is probably a good reason for it. Unless you have a niche use case and know what you are doing, the empty class serves no purpose other than adding useless files to your project
Related
package main.java;
public class Demo {
public static void main(String[] args) {
BClass bClass=new BClass("han","男");
AClass aClass=bClass;
System.out.println(aClass.getSex());
System.out.println(aClass.sex);
}
}
The execution result of this class is
男
null
The results are confusing to me. When the superclass calls the overridden method, the results meet my expectations, but when it calls the overridden variable, the results confuse me.so why does a superclass reference calling an overridden method appear polymorphic, but not if it takes an overridden member variable?Here's the entire code.
package main.java;
public class Demo {
public static void main(String[] args) {
BClass bClass=new BClass("han","男");
AClass aClass=bClass;
System.out.println(aClass.getSex());
System.out.println(aClass.sex);
}
}
package main.java;
public class AClass {
private String name;
public String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
package main.java;
public class BClass extends AClass{
private String sex;
public BClass(String name,String sex) {
this.sex = sex;
super.setName(name);
}
#Override
public String getSex() {
return sex;
}
#Override
public void setSex(String sex) {
this.sex = sex;
}
}
While you can override a method, you can't override a field in a subclass; you are actually just declaring a field with the same name. To allow the field to also be visible in the child class, you can change its visibility to protected or package private (default modifier), if both classes are in the same package. Demo.
public class BClass extends AClass{
public BClass(String name,String sex) {
this.sex = sex;
super.setName(name);
}
#Override
public String getSex() {
return sex;
}
#Override
public void setSex(String sex) {
this.sex = sex;
}
}
public class AClass {
protected String name, sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
Java doesn't allow you to really override a field.
Your BClass actually has two fields named sex, one from AClass, and one from BClass. And Java syntax doesn't really help you finding out which one is meant when you write something like x.sex. It's as if you had defined two different fields, sex_a in AClass and sex_b in BClass, only with the complication that references to both are written like x.sex, without a clear hint which of the two is meant here.
In your case:
Your BClass instance will have its sex_b initialized, and the sex_a empty (null).
aClass.getSex() always calls the most specific method, based on the instance's runtime class, being BClass. So it chooses the method from BClass, returning sex_b, and thus prints the sex.
aClass.sex accesses one of the two sex fields, depending on the variable's compile-time-deducible type, in your case being AClass. So it prints the sex_a value, being null.
Seasoned Java developers typically do their best to avoid this situation, as it can be very confusing.
If the two fields conceptually have the same meaning, do it as you did with the name field, having only one field in the parent class, and have the subclass access it via getters and setters (or by declaring protected visibility for the field).
If the two fields have conceptually different meanings (can an object have two different sexes?), use different names.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
I wanted to make hierarchical builders in Java and noticed that builder inheritance is not possible without a trick. I found some tricks on this page. And I decided to use getThis() trick and it works well.
But it seems very confusing. Please look at codes below.
public class Something {
public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
protected String name;
protected abstract T self();
private T confusing() {
// this method doesn't work.
// compile error:
// Incompatible types. Required: T, Found: AgeAddedBuilder
return new AgeAddedBuilder();
}
public T setName(String name) {
this.name = name;
return self();
}
}
public static class AgeAddedBuilder extends AbstractBuilder<AgeAddedBuilder> {
private int age;
#Override
protected AgeAddedBuilder self() {
return this; // works well
}
public AgeAddedBuilder setAge(int age) {
this.age = age;
return this;
}
#Override
protected Something bulid() {
return super.bulid();
}
}
}
I don't know why overridden self() works but confusing() doesn't although both methods return same type. Why is new AgeAddedBuilder() not a T extends AbstractBuilder<T>?
It doesn't work, because T might not always be AgeAddedBuilder, while the confusing() method always returns that type (imagine your T represents a pet, but instead of making the method a template for returning either cats or dogs, you always return cats.)
If you need an instance of T, then you should keep the T's meta-info in the abstract class, which will help you create instances of T at Runtime.
For example:
public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
protected String name;
private final Class<T> clazz;
public AbstractBuilder(Class<T> clazz) {
this.clazz = clazz;
}
protected abstract T self();
private T confusing() throws Exception {
return clazz.newInstance();
}
public T setName(String name) {
this.name = name;
return self();
}
}
I have two java classes as follows
public class A implements Serializable {
private String name;
private List<String> nameList;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getNameList() {
return nameList;
}
public void setNameList(List<String> nameList) {
this.nameList = nameList;
}
}
public class B implements Serializable {
private String name;
private List<String> nameList;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getNameList() {
return nameList;
}
public void setNameList(List<String> nameList) {
this.nameList = nameList;
}
}
Now I have an object of class A, Aobj, with both the fields initialized. I am using BeanUtils.copyProperties(Bobj, Aobj), but only the name field value is copied into the Bobj however Bobj.nameList is null. Is there a way to deep copy a object so that it copies all the fields including Collections like List, Map etc.
I somewhere heard about Dozer, not sure if that is meant for this purpose.
It is a bit strange that you have 2 different classes that are absolutely identical. But regardless, in order to deep copy one to another just write a 2 static methods in some Util class. One method will take class A and return class B and another will take B and return class A. Do your deep copying by yourself. Also, you can create class C that is the same as your classes A and B and then make your classes A and B just empty classes each extending C. It would give you the same structure, but would make your copying logic easier as you can just work with both A and B as instances of C.
basically I created a Person class and a constructor which sets the name,last name,age of the Person.all the properties of the class were set the private as it should be. I have made setters and getters for all the properties. On the main method I tried to override one of the setters just for practice reason. Its did draw an error saying Person.name not visible which means it cannot access private, Why this is happening, I mean if wasn't overriding the method it would have access. but if I set it to protected mode i will work.
Here is the code:
class Person {
private int age;
private String name;
private String last_name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public Person(int age, String name, String last_name) {
this.age = age;
this.name = name;
this.last_name = last_name;
}
}
public class main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person per = new Person(15,"bb","Sb") {
public void setName(String name) {
this.name = "aaaa";
}
};
per.setName("asdfaf");
System.out.println(per.getName());
}
}
A private member is only accessible in the class in which it is declared.
You created an anonymous sub-class of Person and tried to access a private member of the super-class from the sub-class. This is never allowed.
When developers of a class wish to allow access to certain members of the class to its sub-classes, they set the acess level to protected.
You have created a class named Person and in the following lines you are trying to create an anonymous subclass:
Person per = new Person(15,"bb","Sb") {
public void setName(String name) {
this.name = "aaaa";
}
};
As mentioned in doc:
A subclass does not inherit the private members of its parent class
Here your anonymous subclass is trying to access private field name directly and so is the error. You can use getter/setter which are public. You can also check this related question on SO.
You cannot access private fields from outside your class, even if you are overriding it. You are basically defining a new subclass of Person in your main(), which isn't allowed access to the private field Person.name. However, it can access a protected field.
Basic idea behind overriding is to redefine existing functionality and give new definition to it. If you refer to documentation, private member variables are only accessible in it own class. That why it is not available in your anonymous sub-class implementation.
Note: Generally we do not override setter methods as they are not a functionality.
This is called encapsulation . You can not access private vars from other classes . you can find more description here
I have a homework that specifies to add to an existent project a generic repository layer. The problem that i face is the following. My repository should encapsulate a map that stores the data. What I have until now is the following:
public interface IDObject<T> {
public Comparable<T> getID();
}
public class Person implements IDObject<String> {
private String cnp;
private String name;
private String age;
public Person(String cnp, String name, String age) {
this.cnp = cnp;
this.name = name;
this.age = age;
}
public void setName(String name) { this.name = name; }
public void setCNP(String cnp) { this.cnp = cnp; }
public void setAge(String age) { this.age = age; }
public String getName() { return name; }
public String getCNP() { return cnp; }
public String getAge() {return age; }
public String toString() { return cnp + "-" + name + "-" + age; }
#Override
public Comparable<String> getID() { return getCNP(); } //basically the unique identifier
}
public class Repository<T extends IDObject<?????????>>{
private IMap map;
public Repository() {
map = new Map<???????, T>();
}
...
}
So my problem appears in Repository class. I want to store persons so I will do something like Repository<Person> repo = new Repository<Person>(); But the problem is I don't know how to construct the map in the Repository constructor. In other words I don't know the type of the key. I want the Person's cnp to be the key(which is of Type String), but if I force the map to define the keys as Strings, my repository is no longer generic, because if I want to add some Animal objects that have the key as an integer , the map should be like map = new Map<Integer, T>();.
So the question is how can I still use a construction like Repository<Person> repo = new Repository<Person>(); using the fact that Objects that are stored in a repository implement IDObject and knowing that a repository encapsulates a map which stores the data? How should I get to know the key so I can complete the repository class?
You will have to introduce another generic type:
public class Repository<T, O extends IDObject<T>>
After that you can introduce StringIDRepository as
public class StringIDRepository<O extends IDObject<String>> extends Repository<String, O>
Alternative is to use Map<Object, O>, but that would require you to have in your Repository class getById method that takes Object as argument.
Hope this will help!