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();
}
}
Related
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
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'll try to keep this short. I'm trying to do something like this:
public enum Fruit {
APPLE("Apple", appleHelper::doAppleThing),
ORANGE("Orange", orangeHelper::doOrangeThing);
private String name;
private Function<String, List<T>> fruitFunction;
Fruit(String name, Function<String, List<T>> fruitFunction) {
this.name = name;
this.fruitFunction = fruitFunction;
}
public String getName() {
return name;
}
public <T> List<T> applyFruitFunction(String someString) {
return fruitFunction.apply(someString);
}
}
Such that later, I can have a method like
private <T> List<T> doFruitThing(String someString, Fruit fruit) {
List<T> transformedFruits = fruit.applyFruitFunction(someString);
if (transformedFruits.isEmpty()) {
throw new FruitException("There was no fruit of type " + fruit.getName());
}
return transformedFruits;
}
There's two problems I'm running into here.
doAppleThing and doOrangeThing are not static methods, and ideally will stay that way, and I can't find any way of creating a local instance of appleHelper and orangeHelper to make the method reference work.
Even if I were to make the methods static, enums can't have Type parameters, so there's no way to have Function<String, List<T>> fruitFunction as a field.
Is there a way this can be done? Or a better approach to this?
Enum values can have their own method implementations. So I would write this as:
public enum Fruit {
APPLE("Apple") {
private final AppleHelper helper = new AppleHelper();
#Override
public <T> List<T> applyFruitFunction(String someString) {
return helper.doAppleThing(someString);
}
},
ORANGE("Orange") {
private final OrangeHelper helper = new OrangeHelper();
#Override
public <T> List<T> applyFruitFunction(String someString) {
return helper.doOrangeThing(someString);
}
};
private String name;
Fruit(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract <T> List<T> applyFruitFunction(String someString);
}
However, if you get to the point of needing per-instance state for enum instances, the thing you have is less and less an enum and more of just an abstract base class. It might be better to look into a more OO approach, using a factory/flywheel pattern for example, rather than being tied to a pure enum for this sort of thing. (It's hard to tell for sure because the code in the question is obviously just a simplified example.)
This question already has answers here:
Returning an objects subclass with generics
(4 answers)
Closed 5 years ago.
If this question has already been asked i could not find it.
Here is a simplified example of what i am trying to do.
public static class SuperClass {
private String name;
public <? extends SuperClass> setName(String name)
this.name = name;
return this;
}
}
public static class SubClass extends SuperClass {
private int id;
public void setId(int id) {
this.id = id;
}
}
//Usage
SubClass subclass = new SubClass();
subClass.setName("Some Name").setId(0);
So what i need is for setName to return whatever class its actually called from as oppose to the class its defined in. (In this case it would return an instance of SubClass instead of SuperClass, but if for example SubClass was then extended by SubClass2 it would return an instance of SubClass2)
Is what im asking possible via generics?
You can add a type to the SuperClass declaration and use it in the returned type of the setName() method.
It will force all inherited subclass to return the type declared in their extending declaration to SuperClass.
But to achieve it you should cast this to T in setName().
public class SuperClass<T extends SuperClass<T>> {
private String name;
public T setName(String name) {
this.name = name;
return (T) this;
}
}
And declare subclass in this way :
public class SubClass extends SuperClass<SubClass> {
...
public void setId(int i) {
...
}
...
}
And now you could do :
SubClass subclass = new SubClass();
subclass.setName("Some Name").setId(0);
Another way to address the problem :
Using covariant return types in the overrided methods will allow you to specify subclass in the returned type. You can use it instead of generics.
The single thing to notice : you will have to be careful to define explicitly the return type by overriding the method in each subclass.
Without generics, nothing will force you to do it (but an unit test).
public class SuperClass {
private String name;
public SuperClass setName(String name) {
this.name = name;
return this;
}
}
public class SubClass extends SuperClass {
#Override
public SubClass setName(String name) {
super.setName(name);
return this;
}
public void setId(int i) {
...
}
}
I need help fixing my code with the basic concepts listed above. To save from clutter, I took a screen shot of the directions here: https://imgur.com/SdiotUi
However, when I run my code it isn't working. I know there are a lot of errors but I'm having trouble fixing them even though I've spent the past few hours googling the correct way to do this.
When I create the first constructors I am not sure if I am assigning the name and legs correctly, I am having trouble returning "true", I get an error calling the parent class taking one argument, and I don't think I am overriding the abstract class correctly.
My code:
public class Animal1 {
private String animalName;
public int numberOfLegs;
public Animal1(String name){
name = animalName;
name = "John";
}
public Animal1(String name, int legs){
name = animalName;
legs = numberOfLegs;
name = "Jack";
legs = 4;
}
public String getName(){
return animalName;
}
public int getLegs(){
return numberOfLegs;
}
public void isAMammal(){
return true;
}
public void isCarnivorous(){
return true;
}
public abstract class getHello{
}
}
public class Cat1 extends Animal1{
public Cat1(String name){
Animal1.name;
}
public abstract class getHello{
return "Meow";
}
}
public class Dog1 extends Animal1{
public Dog1(String name){
Animal1.name;
}
public abstract class getHello{
return "Woof";
}
}
public abstract class Animal1 { // If you want to have an abstract method, declare the class as abstract
private final String animalName;
private final int numberOfLegs; // better of using private and make it final since it's not going to change.
public Animal1(final String name, final int legs){ //better making the input parameters final since they are not supposed to be changed
//name = animalName;
//legs = numberOfLegs;//it assigned the field to an input parameter. that will take no effect on the object created.
animalName = name;
numberOfLegs = legs;
}
public String getName(){
return animalName;
}
public int getLegs(){
return numberOfLegs;
}
public boolean isAnimal(){ //boolean function needs a return type too!!
return true;
}
public boolean isCarnivorous(){
return true;
}
public abstract String getHello(); // an abstract method has same requirement as a normal method besides the abstract modifier. it will need a return type. And it ends with a semicolon
}
public class Cat1 extends Animal1{
public Cat1(final String name){
super(name, 4); //use super to call parent constructor
}
#Override
public String getHello(){
return "Meow";
}
}
public class Dog1 extends Animal1{
public Dog1(final String name){
super(name, 4);
}
#Override
public String getHello(){
return "Woof";
}
}
First, it looks like a few of your methods are declared as classes. I assume you wanted to make them abstract methods. They need to be changed to:
public abstract String getHello();
Note that abstract methods can only be declared in an abstract class. So, you need to redefine Animal1 as abstract.
public abstract class Animal1
Next, when you implement the abstract method, you define it as
public String getHello()
If you are using an IDE like Eclipse it will automatically offer to generate this method.
Finally, when using your constructor in your child classes like Cat1, you are trying to set "name" as if it was a static variable and bypassing the constructor you already had set for Animal1. The best way to correct this is to change the constructor in Cat1 and Dog1 to call the super constructor.
public Cat1(String name){
super(name);
}