Java generics restrictions with interfaces - java

abstract class
public abstract class Animal {
private int id;
private String name;
public Animal(int id, String name) {
this.id = id;
this.name = name;
}}
_child of animal 1
public class Tiger extends Animal implements Dangerous {
public Tiger(int id, String name) {
super(id, name);
} }
_child of animal 2
public class Panda extends Animal implements Harmless{
public Panda(int id, String name){
super(id, name);
}}
_
Two attribute interfaces
public interface Dangerous {}
public interface Harmless {}
public class Zoo {
public static <T extends Animal & Harmless> void tagHarmless(Animal animal) {
System.out.println("this animal is harmless");
}
public static <T extends Animal & Dangerous> void tagDangerous(Animal animal) {
System.out.println("this animal is dangerous");
}}
public class App {
public static void main(String[] args) {
Animal panda = new Panda(8, "Barney");
Animal tiger = new Tiger(12, "Roger");
Zoo.tagHarmless(panda);
Zoo.tagHarmless(tiger);
}}
-result
this animal is harmless
this animal is harmless
Process finished with exit code 0
i try to restrict the methods of the class "zoo" with the interfaces "Dangerous" and "Harmless".
with the code
public static <T extends Animal & Harmless> void tagHarmless(Animal animal).
The Tiger doesnt have this Interface, so it actually should not work, does it?
But the tiger can also be added into this method tagHarmless.
I don't see the mistake.
Thanks for help.

You are declaring a generic type parameter T, but your method is never using it. Your method accepts an Animal argument, which means any Animal is acceptable.
It should be:
public static <T extends Animal & Harmless> void tagHarmless(T animal) {
System.out.println("this animal is harmless");
}
As for your main method, you are assigning the Panda and Tiger instances to Animal variables. Therefore, changing tagHarmless as I suggested means that neither the panda nor the tiger variables can be passed to tagHarmless (since an Animal doesn't implement Harmless).
If you change your main to:
Panda panda = new Panda(8, "Barney");
Tiger tiger = new Tiger(12, "Roger");
Zoo.tagHarmless(panda);
Zoo.tagHarmless(tiger);
The call to Zoo.tagHarmless(panda); will pass compilation, and the call to Zoo.tagHarmless(tiger); will not.

Related

Java: make package level constructor in a class accessible for outer packages. Allow only certain classes inside project access to constructor

I'm developing a library and trying to keep everything organized. Thus, I have nested package structure and a single class that is supposed to have access to constructors to all other classes:
This is my project structure:
src
main
java
main
Main.java
zoo
Zoo.java
animals
Animal.java
mammals
Dog.java
fish
Salmon.java
birds
Falcon.java
This is the code I have in a main method:
Main.java:
Zoo zoo = new Zoo(password);
Animal dog = zoo.getDog(name);
Animal salmon = zoo.getSalmon(name);
Animal falcon = zoo.getFalcon(name);
I want to prevent a user from being able to create an animal directly (from outside of the zoo package):
Animal dog = new Dog("Charlie"); //error - constructor isn't public
However I'm not sure how to accomplish it. I could put all classes inside the zoo package and make animal constructors only package-level accessible. However, I would have to sacrifice the package structure and I'd rather not do that.
Zoo.java:
public class Zoo {
private String password;
public Zoo(String password) {this.password = password;}
public Dog getDog(String name) {return new Dog(name);}
public Salmon getSalmon(String name) {return new Salmon(name);}
public Falcon getFalcon(String name) {return new Falcon(name);}
}
Animal.java:
public abstract class Animal {
protected String name;
public Animal(String name) {this.name = name;}
}
animals:
public class Dog extends Animal {
public Dog(String name) {super(name);}
}
public class Salmon extends Animal {
public Salmon(String name) {super(name);}
}
public class Falcon extends Animal {
public Falcon(String name) {super(name);}
}
So what can be done to accomplish the above? Pehaps there exists some pattern for it?
To preserve package structure and make sure the user will instantiate animals using Zoo instance,
you probably have to use private Factories in Zoo class. However this seems to be a very awkward solution:
public class Falcon extends Animal {
protected Falcon() {
}
protected static Falcon create() {
return new Falcon();
}
}
---
public class Dog extends Animal {
protected Dog() {
}
protected static Dog create() {
return new Dog();
}
}
---
public class Zoo {
public Falcon getFalcon() {
return new FalconFactory().get();
}
public Dog getDog() {
return new DogFactory().get();
}
private static class FalconFactory extends Falcon {
private Falcon get() {
return create();
}
}
private static class DogFactory extends Dog {
private Dog get() {
return create();
}
}
}
I don't think this is a good desing, but indeed this force user to use Zoo instance to create animals.
Of course a user still may create her own Factory that inherits from Falcon or Dog.

Abstract class values are null after calling super

I have the following program:
public class Driver {
public static void main(String[] args) {
Animal dog = new Dog("larry");
dog.speak();
}
}
public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public abstract void speak();
}
public class Dog extends Animal {
private String name; // is this even needed?
public Dog(String name) {
super(name);
}
#Override
public void speak() {
System.out.println("I am " + name);
}
}
Running this program prints I am null, which is not what I want.
Why doesn't it just use the Animal variable defined name and print out larry?
What is the proper way to do this?
If I remove the name from the Dog class, is it possible to reference the Animal name variable while still keeping it private?
If so, how?
The name variable used in
System.out.println("I am " + name);
is the one defined in the Dog class. It is never set, hence null is printed.
There is no need to define name in both Animal and Dog. My suggestion would be to:
remove name from Dog
change the visibility of name in Animal to protected
If you want to keep the access to name as private, add a "getter" method for name to Animal, thus:
public class Animal {
private String name;
public String getName() { return name; }
}
public class Dog {
#Override
public void speak() {
System.out.println("I am " + getName());
}
}
You don't need the variable name in Dog; it is a separate variable from the one in Animal. The Animal constructor initializes the name in Animal correctly, but the speak method in Dog refers to the uninitialized name variable in Dog; the variable in Dog is the one that is in scope inside the Dog class code. Delete the name variable in Dog to avoid confusion.
But to keep name private in Animal and access it in a subclass, provide a getter method in Animal.
public String getName() { return name; } // or protected
Then you can call it in Dog:
System.out.println("I am " + getName());
Output:
I am larry

What happens when parent class object is assigned child class object?

This following code gives the output as :
Output:
Animal
Dog
Animal
I'm confused why "a.type" outputs as "Animal" even after the assignment "a=b". Why is it so?
Another observation was when I don't declare variable - "String type" inside Dog class. Then I get the output as :
Output:
Dog
Dog
Dog
My code:
//Parent class
class Animal {
String type;
public Animal(){
this.type= "Animal";
}
}
//Child class
class Dog extends Animal {
String type;
public Dog(){
this.type ="Dog";
}
}
//Main Class To Test
class TestDog{
Animal a = new Animal();
Dog b = new Dog();
Animal c = new Dog();
a = b;
System.out.println(a.type);
System.out.println(b.type);
System.out.println(c.type);
}
First a didactic point. You state in your tile:
What happens when parent class object is assigned child class object?
Please understand that you're assigning a child class object to a parent type variable. This may seem picky, but it's an important distinction and gets to the core of how Java implements OOPs and uses reference variables. Also the parent type might not even be a class, but could be an interface (a "pure" type).
As for your confusion, you're adding a type field to both the parent and the child class. Don't, since fields aren't overridden. Add it to the Parent only. Make it protected or give it getters and setters.
For example:
class Animal {
private String type;
public Animal() {
this.type = "Animal";
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
// Child class
class Dog extends Animal {
String type;
public Dog() {
setType("Dog");
}
}
// Main Class To Test
class TestDog {
public static void main(String[] args) {
Animal a = new Animal();
Dog b = new Dog();
Animal c = new Dog();
a = b;
System.out.println(a.getType());
System.out.println(b.getType());
System.out.println(c.getType());
}
}

Spring Boot custom implementations for Spring Data repositories with MappedSuperclass and subclasses

Here is a simplified working code. There are a mapped superclass and two its subclasses (in real life superclass of course contains more fields)
Animal.java
#MappedSuperclass
#lombok.NoArgsConstructor
#lombok.RequiredArgsConstructor
public abstract class Animal {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#lombok.Getter
private Long id;
#lombok.Getter
#lombok.NonNull
private String name;
}
Cat.java
#Entity
#Table
#lombok.NoArgsConstructor
public class Cat extends Animal {
public Cat(Integer weight, String name) {
super(name);
this.weight = weight;
}
#lombok.Getter
private Integer weight;
}
Dog.java
#Entity
#Table
#lombok.NoArgsConstructor
public class Dog extends Animal {
public Dog(Integer age, String name) {
super(name);
this.age = age;
}
#lombok.Getter
private Integer age;
}
AnimalRepositoryImpl and AnimalRepository contain some shared code for Cat and Dog repositories.
AnimalRepository.java
#NoRepositoryBean
public interface AnimalRepository<T extends Animal> extends JpaRepository<T, Long> {
List<T> findAllByName(String name);
}
AnimalRepositoryImpl.java
public class AnimalRepositoryImpl<T extends Animal> {
#Autowired
AnimalRepository<T> animalRepository;
public List<T> findAllBySomeLogic() {
return animalRepository.findAll().stream().filter(animal -> !animal.getName().startsWith("Z")).collect(Collectors.toList());
}
}
Now I can add all CatRepositories and it still works (and works correctly).
CatRepository.java
#Transactional
public interface CatRepository extends AnimalRepository<Cat>, CatRepositoryCustom {
}
CatRepositoryCustom.java
public interface CatRepositoryCustom {
public List<Cat> findAllBySomeLogic();
}
CatRepositoryImpl.java
public class CatRepositoryImpl extends AnimalRepositoryImpl implements CatRepositoryCustom {
}
Here is a test class which still uses only cat repository.
AnimalRepositoryTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#ActiveProfiles(profiles = "test")
public class AnimalRepositoryTest {
#After
public void tearDown() {
catRepository.deleteAll();
}
#Autowired
private CatRepository catRepository;
#Test
public void shouldFindAllBySomeLogic() {
// given
catRepository.save(Lists.newArrayList(new Cat(2000, "Luna"), new Cat(2500, "Zoe"), new Cat(1800, "Toby")));
// when
List<Cat> cats = catRepository.findAllBySomeLogic();
// then
assertThat(cats.stream().map(c -> c.getName()).collect(Collectors.toList()), containsInAnyOrder("Luna", "Toby"));
}
#Test
public void shouldFindAllByName() {
// given
catRepository.save(Lists.newArrayList(new Cat(2000, "Luna"), new Cat(2500, "Zoe"), new Cat(1800, "Toby")));
// when
List<Cat> cats = catRepository.findAllByName("Luna");
// then
assertThat(cats.stream().map(c -> c.getName()).collect(Collectors.toList()), containsInAnyOrder("Luna"));
}
}
The way I've coded it was inspired mostly by this question (but my case is more complicated).
So... the main question. - How to add repositories for Dog (almost identical to Cat ones) and not to get something like NoUniqueBeanDefinitionException: No qualifying bean of type...? I've tried some variations with #Qualifier but seems it doesn't work in this case. Or maybe I'm doing it completely wrong.
I see at least one failure related to the generic definition of your classes. The class CatRepositoryImpl extends the classe AnimalRepositoryImpl without any generic Types. (See the following two code snippets of your post)
public class CatRepositoryImpl extends AnimalRepositoryImpl implements CatRepositoryCustom {
}
public class AnimalRepositoryImpl<T extends Animal> {
}
In my opinion it should look like.
public class CatRepositoryImpl extends AnimalRepositoryImpl<Cat> implements CatRepositoryCustom {
}
Beside that, I would avoid doing logic related things in a Repository class and move it to a Service level.

java- calling sub-class from a list

I have this code:
public abstract class animal {
public final static int elephent = 1;
public final static int dog = 2;
and two sub-classes:
public class elephant extends animal {
public final static int type = animal.elephent;
public elephant (String name){
super(name);
}
}
public class dog extends animal {
public final static int type = animal.dog;
public dog (String name){
super(name);
}
}
now, say I have a list of Chars with the letters E- elephant and D- dog.
and an empty list of animals class of the same size.
and for every char on the first list I want to create a new instance of the right animal.
example: ["d","e","d"]
would give me a list of: [new dog, new elephant, new dog]
hope I made myself clear,
thanks in advance for the help.
This design is not optimal. You are indicating the type with an integer variable, which really is not a good idea.
First improvement: Make the type indication an enum.
public enum AnimalType {
ELEPHANT, DOG
}
Now add a type field in your animal class:
public abstract class Animal {
private final AnimalType type;
private final String name;
protected Animal(AnimalType type, String name) {
this.type = Objects.requireNonNull(type);
this.name = Objects.requireNonNull(name);
}
// more fields and methods here
}
An elephant then looks like that (dog is similar):
public class Elephant extends Animal {
public Elephant(String name) {
super(AnimalType.ELEPHANT, name);
}
// more fields and methods here
}
The main disadvantage: Each time you add a new animal type, you must add a new class and add a type to the enumeration. This is not the best design. Additionally, the type enum is not really needed, as the sub types already hold the type information
An instance of class Elephant is an elephant (dog the same). It does not need the type field.
Second improvement: Delete the type indication completely. No integers, no enums. Just have the abstract class and the sub classes.
Now your question, how to get the correct instance from any character input. This is called a mapping. You want to map
the character 'E' to the class Elephant.
the character 'D' to the class Dog.
This can be achieved by a Java Map:
Map<Character, Class<? extends Animal>> charToAnimal = new HashMap<>();
charToAnimal.put('E', Elephant.class);
charToAnimal.put('D', Dog.class);
Class<? extends Animal> animalClass = charToAnimal.get('E');
String name = ...;
Animal animal = animalClass.getConstructor(String.class).newInstance(name); // will be an Elephant instance
This map should be maintained in any class you need that behavior, or maybe in the main method if you are just learning how to do that.
Note, that I used a Java mechanism called reflection, just to create an instance, as there is no other generic way to handle the instantiation.
Another approach would be a method that does the same:
public Animal createAnimal(char c, String name) {
if (c == 'E') {
return new Elephant(name);
} else if (c == 'D') {
return new Dog(name);
} else {
throw new IllegalArgumentException(c);
}
}
Either way, you have to add not only a ne animal sub class, but you have to add an entry into the map (see above) or an if branch to the method.
EDIT, as I thought again over this scenario.
You could go with the enum approach and put the class instantiation into this enum. Take the animal classes as above and the following type enum (not checked):
public enum AnimalType {
ELEPHANT('E', Elephant.class),
DOG('D', Dog.class);
private static final Map<Character, Class<? extends Animal>> CHAR_TO_ANIMAL = new HashMap<>();
AnimalType(char c, Class<? extends Animal> animalClass) {
CHAR_TO_ANIMAL.put(c, animalClass)
}
public Animal createAnimal(char c, String name) {
if (c == 'E') {
return new Elephant(name);
} else if (c == 'D') {
return new Dog(name);
} else {
throw new IllegalArgumentException(c);
}
}
}
So one of the things you may want to consider is a switch-case statement. So in Java, you could do something like this:
// get a char from the list.
char animal;
switch(animal)
{
case'e':
Elephant varName = new Elephant("Dumbo");
newList.add(varName);
break;
}
I've not included everything here, but this should get you started. You will need to look up iterating (looping) through a data structure.
I will be honest, it's been a while since I've written any Java, but this is one way you could do this. There are other ways to do this as well, such as using an if block as well.
Hope this helps.
I think what u need is an static factory method returns an instance.Here is one way of doing it.
Abstract Class:
public abstract class animal {
public final static char elephent = 'E';
public final static char dog = 'D';
}
Elephant Class:
public class Elephant extends Animal {
private char myType;
private String name;
public Elephant(char type, String name) {
super();
this.myType = type;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getMyType() {
return myType;
}
public void setMyType(char myType) {
this.myType = myType;
}
}
Dog Class:
public class Dog extends Animal {
private char myType;
private String name;
public Dog(char type, String name) {
super();
this.myType = type;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getMyType() {
return myType;
}
public void setMyType(char myType) {
this.myType = myType;
}
}
Factory Class:
public class FactoryMethod {
static char getAnimalIndex(char type){
switch (type) {
case 'E':
case 'e':
return Animal.ELEPHANT;
case 'D':
case 'd':
return Animal.DOG;
default:
throw new IllegalArgumentException(String.valueOf(type));
}
}
public static Animal getInstance(char type, String name){
Animal myCategory = null;
switch (getAnimalIndex(type)) {
case Animal.ELEPHANT:
myCategory = new Elephant(type,name);
break;
case Animal.DOG:
myCategory = new Dog(type,name);
break;
}
return myCategory;
}
}
Usage:
if u need to use Animal class index or as u with the character from the list this factory method works.
To get instance:
//using Animal index
FactoryMethod.getInstance(Animal.ELEPHANT,"Elephant");
FactoryMethod.getInstance(Animal.DOG,"Dog");
//using characters in list
FactoryMethod.getInstance('character_in_list_here',"Name OF The Animal Here");
Since it is a static method u can use without using FactoryMethod instance.
I hope this is what u needed.

Categories