Using a Custom-Defined Comparator in a Constructor - java

I'm having difficulty using Comparators in Constructors. When I try the following code:
InsertionSorter is = new InsertionSorter(bookList.toArray(new Comparable[bookList.size()]), new GenreComparator(), SortType.ASC);
I get this error:
no suitable constructor found for InsertionSorter(java.lang.Comparable[],sort.GenreComparator,sort.SortType)
constructor sort.InsertionSorter.InsertionSorter(java.lang.Comparable[],java.util.Comparator<java.lang.Object>,sort.SortType) is not applicable
(actual argument sort.GenreComparator cannot be converted to java.util.Comparator<java.lang.Object> by method invocation conversion)
constructor sort.InsertionSorter.InsertionSorter(java.lang.Comparable[],sort.SortType) is not applicable
(actual and formal argument lists differ in length)
Here are the useful code snippets:
AbstractSorter.java:
abstract class AbstractSorter {
protected Comparable[] values;
protected Comparator<Object> cmp;
protected SortType st;
protected abstract void doSort();
protected AbstractSorter(Comparable[] init, SortType type) {
values = new Comparable[init.length];
System.arraycopy(init, 0, values, 0, init.length);
cmp = null;
st = type;
}
protected AbstractSorter(Comparable[] init, Comparator<Object> comp, SortType type) {
values = new Comparable[init.length];
System.arraycopy(init, 0, values, 0, init.length);
cmp = comp;
st = type;
}
public Comparable[] getValues() {
return values;
}
}
class InsertionSorter extends AbstractSorter {
public InsertionSorter(Comparable[] init, SortType type) {
super(init, type);
}
public InsertionSorter(Comparable[] init, Comparator<Object> comp, SortType type) {
super(init, comp, type);
}
#Override
public void doSort() {
// sorts values
}
}
enum SortType {ASC, DSC};
Book.java:
public class Book implements Cloneable, Comparable<Book> {
private Person author; // implementation details of Person don't matter here
private String title, isbn;
private int year;
private BookGenre genre;
public Book(Person authorInit, String titleInit, String isbnInit,
int yearInit, BookGenre genreInit) {
author = authorInit;
title = titleInit;
isbn = isbnInit;
year = yearInit;
genre = genreInit;
}
#Override
public String toString() {
return author.toString() + " " + title + " " + isbn + " " + year
+ " " + genre;
}
#Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
#Override
public int compareTo(Book other) {
return author.compareTo(other.author);
}
public Person getAuthor() {
return author;
}
public String getTitle() {
return title;
}
public String getIsbn() {
return isbn;
}
public int getYear() {
return year;
}
public BookGenre getGenre() {
return genre;
}
}
class TitleComparator implements Comparator<Book> {
#Override
public int compare(Book a, Book b) {
return a.getTitle().compareToIgnoreCase(b.getTitle());
}
}
class GenreComparator implements Comparator<Book> {
#Override
public int compare(Book a, Book b) {
return a.getGenre().compareTo(b.getGenre());
}
}
enum BookGenre { COMIC, MYSTERY, SCIENCE, TRAVEL };
EDIT Thanks to Rohit for a solution to this problem, but now I'm having a related problem. In the method doSort(), I have the code snippet
cmp.compare(values[j-1], values[j])
(don't worry, I have checks in place to make sure this isn't called if cmp == null. This gives the following error:
method compare in interface java.util.Comparator<T> cannot be applied to given types;
required: capture#1 of ? extends java.lang.Object,capture#1 of ? extends java.lang.Object
found: java.lang.Comparable,java.lang.Comparable
reason: actual argument java.lang.Comparable cannot be converted to capture#1 of ? extends java.lang.Object by method invocation conversion
Note that I have changed the above in AbstractSort.java to replace Comparable<Object> with Comparable<? extends Object>

GenreComparator class implements Comparator<Book>. So you can't pass an instance of that class where a Comparator<Object> is required. Both are non-compatible.
You can however change Comparator<Object> to Comparator<? extends Object> in your constructor, and also the type of field cmp in AbstractSorter class.

Related

how to define parameterized constructor of abstract class in child class in java

how to define parameterized constructor of abstract class in child class in java
abstract class Car {
protected boolean isSedan;
protected String seats;
public Car(boolean isSedan, String seats) {
this.isSedan = isSedan;
this.seats = seats;
}
public boolean getIsSedan() {
return this.isSedan;
}
public String getSeats() {
return this.seats;
}
abstract public String getMileage();
}
public class WagonR extends Car{
protected int mileage;
protected boolean isSedan;
public WagonR(int mileage) {
super(isSedan,seats);
this.mileage=mileage;
}
}
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
int carType = Integer.parseInt(bufferedReader.readLine().trim());
int carMileage = Integer.parseInt(bufferedReader.readLine().trim());
Car wagonR = new WagonR(carMileage);
wagonR.printCar("WagonR");
}
}
While passing isSedan and seats parameters in super block in WagonR constructor, getting compilation error "Cannot refer to an instance field isSedan while explicitly invoking a constructor" and "Cannot refer to an instance field seats while explicitly invoking a constructor"
Constraint is while execution only one parameter will be passed like WagonR(carMileage).
I was doing mistake by passing parameter names in super block rather than passing parameter values using which I wanted to invoke Car constructor.
//incorrect
public WagonR(int mileage) {
super(isSedan,seats);
this.mileage=mileage;
}
//correct
public WagonR(int mileage) {
super(false,"4");
this.mileage=mileage;
}
Your WagonR class shoud be like this:
public class WagonR extends Car{
protected int mileage;
protected boolean isSedan;
public WagonR(int mileage) {
super(false, "4");
this.mileage=mileage;
}
public WagonR(int mileage, boolean isSedan, String seats) {
super(isSedan, seats);
this.mileage=mileage;
}
// And don't forget override method
#Override
public String getMileage() {
}
}

how to implement fluent builder with inheritance in java

problem
I want to create a class with a fluent builder, both of which can be inherited and extended. Base class should have all the common and mandatory fields, children should have different optional fields
simple example below (best, simplistic usecase I could come up with ;p)
base: Animal
name
age
static Builder
impl: Snake extends Animal
length
static Builder extends Animal.Builder
impl: Spider extends Animal
numberOfLegs
static Builder extends Animal.Builder
and I'd like to use it in one of those ways (most preferred one is the first one):
Spider elvis = Spider.name("elvis").age(1).numberOfLegs(8).build();
Spider elvis = Spider.builder().name("elvis").age(1).numberOfLegs(8).build();
Spider elvis = new Spider.Builder().name("elvis").age(1).numberOfLegs(8).build();
what I want to achieve is
user of this builder will have to provide some minimal information (so the system can work without problems), otherwise he won't be able to build that object
all the optional fields can be declared, with no particular order, after mandatory fields are there
it is possible that I'll need to add some mandatory fields for children, but that can be handled with ease by just changing the first method called in the builder
I don't want to have any casts outside those classes (here: in Main), but I don't mind them inside this code (here: in Animal or Spider)
so far I failed and I'd be very grateful if you could please help me find a way out of it :)
or maybe there is just a different approach that I should think about?
most valuable sources I used
http://blog.crisp.se/2013/10/09/perlundholm/another-builder-pattern-for-java
http://egalluzzo.blogspot.com/2010/06/using-inheritance-with-fluent.html
Generic fluent Builder in Java
work done so far
the code so far can be found below. there are some traces of the things I tried and failed, there are some unused or just weird stuff (best example is IBuildImpl). Those are left to give you an understanding of what I tried, but if you think that this needs moderation - please let me know and I'll clean them up
Base
package fafafa;
public abstract class Animal<T> {
String name; //mandatory field, one of many
Integer age; //mandatory field, one of many
public String getName() {
return name;
}
#Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
interface IName {
IAge name(String name);
}
interface IAge {
IBuild age(Integer age);
}
interface IBuild<T extends Animal<T>> {
T build();
}
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
implements IName, IAge, IBuild<T> {
protected T objectBeingBuilt;
protected abstract B that();
protected abstract T createEmptyObject();
Builder(){
this.objectBeingBuilt = createEmptyObject();
System.out.println();
}
#Override
public IAge name(String name) {
objectBeingBuilt.name = name;
return that();
}
#Override
public IBuild age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
// #Override
// public T build() {
// return objectBeingBuilt;
// }
}
}
Impl
package fafafa;
public class Spider extends Animal<Spider> {
Integer numberOfLegs; //optional field, one of many
private Spider() {
}
public Integer getNumberOfLegs() {
return numberOfLegs;
}
#Override
public String toString() {
return "Spider{" +
"numberOfLegs='" + numberOfLegs + '\'' +
"} " + super.toString();
}
// public static Builder<Spider, Builder> name(String name) {
// return (Builder) new Builder().name(name);
// }
interface INumberOfLegs {
IBuild numberOfLegs(Integer numberOfLegs);
}
interface IBuildImpl extends IBuild<Spider>, INumberOfLegs {
#Override
Spider build();
}
public static class Builder extends Animal.Builder<Spider, Builder> implements IBuildImpl {
#Override
protected Builder that() {
return this;
}
#Override
protected Spider createEmptyObject() {
return new Spider();
}
public IBuild numberOfLegs(Integer numberOfLegs) {
objectBeingBuilt.numberOfLegs = numberOfLegs;
return that();
}
public Spider build() {
return objectBeingBuilt;
}
}
}
Main
package fafafa;
public class Main {
public static void main(String[] args) {
Spider build = new Spider.Builder().name("elvis")
.age(1)
.numberOfLegs(8) //cannot resolve method numberOfLegs
.build();
System.out.println(build);
}
}
Looks like to many generics in a code, I've tried to simplify it a little.
Animal
package come.stackoverflow.builder;
public abstract class Animal {
private final String name; //mandatory field, one of many
private final Integer age; //mandatory field, one of many
Animal(final String name, final Integer age) {this.name = name; this.age = age;}
public String getName() {return name;}
public Integer getAge() {return age;}
#Override public String toString() {return String.format("Animal {name='%s', age='%s'}'", name, age);}
interface IBuild<T> {
T build();
}
public abstract static class AnimalBuilder<B extends AnimalBuilder, T extends Animal> implements IBuild<T> {
String name;
Integer age;
public B name(final String name) {this.name = name; return (B) this;}
public B age(final Integer age) {this.age = age; return (B) this;}
}
}
Spider
package come.stackoverflow.builder;
public class Spider extends Animal {
private final Integer numberOfLegs; //optional field, one of many
private Spider(final String name, final Integer age, final Integer numberOfLegs) {super(name, age); this.numberOfLegs = numberOfLegs;}
public Integer getNumberOfLegs() {return numberOfLegs;}
#Override public String toString() {return String.format("Spider {numberOfLegs='%s'}, %s", getNumberOfLegs(), super.toString());}
public static class SpiderBuilder extends AnimalBuilder<SpiderBuilder, Spider> {
Integer numberOfLegs;
public SpiderBuilder numberOfLegs(final Integer numberOfLegs) {this.numberOfLegs = numberOfLegs; return this;}
public Spider build() {return new Spider(name, age, numberOfLegs);}
}
}
Main Test
import come.stackoverflow.builder.Spider;
public class Main {
public static void main(String[] args) {
Spider build = new Spider.SpiderBuilder()
.name("elvis").numberOfLegs(8).age(1)
.build();
System.out.println(build);
}
}
Execution Result:
Spider {numberOfLegs='8'}, Animal {name='elvis', age='1'}'
The problem of your code is the interface:
interface IAge {
IBuild age(Integer age);
}
This will always return the basic IBuild interface with no parameter, no matter, if the implementation implements it with some argument. Actually even returning it with the parameter wouldn't extend the builder with additional methods.
The parameter in the builder needs to be the extended builder, and not the type to be built.
All interfaces for the common parameters need to be parametrized with it to allow propper continuation.
Here is a suggestion:
1. Don't use IName interface. Replace it with static entry method of the builder
2. Parametrize IAge interface
3. No common builder needed. It can be replaced with inline lambda implementation
Here is the code:
#FunctionalInterface
public interface IAge<B> {
B age(Integer age);
}
public class AnimalBuilder implements IBuild<Animal> {
private final String name;
private final Integer age;
private Integer numberOfLegs;
private AnimalBuilder(String name, Integer age) {
this.name = name;
this.age = age;
}
// Builder entry method
public static IAge<AnimalBuilder> name(String name) {
return age -> new AnimalBuilder(name, age);
}
public AnimalBuilder numberOfLegs(int value) {
numberOfLegs = value;
return this;
}
#Override
public Animal build() {
return new Animal(name, age, numberOfLegs);
}
}
This allows following usage:
AnimalBuilder.name("elvis").age(1).numberOfLegs(8).build();
The problem is in the abstract builder :
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
implements IName, IAge, IBuild<T> {
...
#Override
public IAge name(String name) {
objectBeingBuilt.name = name;
return that();
}
#Override
public IBuild age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
So, all your concrete builders return the same IBuild<T> interface when you invoke the age() method.
and as you see :
interface IBuild<T extends Animal<T>> {
T build();
}
this interface doesn't allow to return a object where you have methods to set properties with your builder.
When you invoke the name() method, you also don't get the builder :
interface IAge {
IBuild age(Integer age);
}
You should declare age() and name() in the abstract builder like that :
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>{
...
public B name(String name) {
objectBeingBuilt.name = name;
return that();
}
public B age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
In this way, at the compile time, the concrete builder will return the builder of the animal you are creating when you will invokebuilder.age(..).
Besides, I don't understand why having a builder interface for name and another one for age. What is interest to handle IAge and IName interfaces ?
It seems a too low level information to be useful in your builder.
Why not simply declaring you base builder like that :
public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
implements IBuild<T> {
protected T objectBeingBuilt;
protected abstract B that();
protected abstract T createEmptyObject();
Builder(){
this.objectBeingBuilt = createEmptyObject();
System.out.println();
}
public B name(String name) {
objectBeingBuilt.name = name;
return that();
}
public B age(Integer age) {
objectBeingBuilt.age = age;
return that();
}
}
I have not tested the code.

How to instantiate this class parametrized by bonded interface?

I've got 3 interfaces:
public interface IAggregable<TElement extends IAggregable<TElement, TResult>, TResult> {
TResult aggregate(TResult intermediateResult);
}
public interface IDeeplyCloneable<TElement extends IDeeplyCloneable<TElement>> {
TElement deepClone();
}
public interface IContainer<TElement extends IAggregable<TElement, TResult> & IDeeplyCloneable<TElement>, TResult> {
TResult aggregateAllElements();
TElement cloneElementAtIndex(int index);
}
Then there are two classes that implement those 2 first interfaces:
public class Person implements IAggregable<Person, Integer>, IDeeplyCloneable<Person> {
private int age;
public Integer aggregate(Integer intermediateResult) {
if (intermediateResult == null) {
return age;
}
return age + intermediateResult;
}
public Person deepClone() {
Person clone = new Person();
clone.age = age;
return clone;
}
#Override
public String toString() {
return "Person [age=" + age + "]";
}
}
and almost exactly the same
public class Car implements IAggregable<Car, Integer>, IDeeplyCloneable<Car> {
private int horsepower;
public Integer aggregate(Integer intermediateResult) {
if (intermediateResult == null) {
return horsepower;
}
return horsepower + intermediateResult;
}
public Car deepClone() {
Car clone = new Car();
clone.horsepower = horsepower;
return clone;
}
#Override
public String toString() {
return "Car [horsepower=" + horsepower + "]";
}
}
then there's finally UselessContainer which suppose to implement IContainer and be able to hold both Person and Car and any other objects of any other class that implements IAggregable and IDeeplyCloneable.
public class UselessContainer<TElement extends IAggregable<TElement, TResult> & IDeeplyCloneable<TElement>, TResult> implements IContainer<TElement, TResult> {
private ArrayList<TElement> list;
public UselessContainer() {
this.list = new ArrayList<>();
}
public void add(TElement element) {
list.add(element);
}
#Override
public TResult aggregateAllElements() {
return null;
}
#Override
public TElement cloneElementAtIndex(int index) {
return null;
}
#Override
public String toString() {
return list.toString();
}
}
Question : How to create object of class UselessContainer?
I've tried that: UselessContainer<? extends IAggregable<?, Integer> & IDeeplyCloneable<?>, Integer> container;
You have marked your UselessContainer to be bound BOTH to IAggregable and IDeeplyCloneable. Please look at the & sign which indicates both of the interfaces must be implemented by business entity to be added to the list.
In order to use it in code - just create instance of UselessContainer without specyfing concrete generics types:
UselessContainer uc = new UselessContainer();
uc.add(new Person()); // works!
uc.add(new Integer(1)); // won't compile
uc.add(new Car()); // works!
I just tried it in my Editor and it works (JDK8).
EDIT:
You may create wrapping class:
class SimpleContainer {
public <TElement extends IAggregable<TElement, TResult> & IDeeplyCloneable<TElement>, TResult> void add(TElement el) {
UselessContainer<TElement, TResult> uc = new UselessContainer<>();
uc.add(el);
}
}
and use it:
SimpleContainer sc = new SimpleContainer();
sc.add(new Person());
You have 2 conditions you want to meet for UselessContainer<A, B> (well shorten this to U<A,B>):
(1) Cars can be added to U<A, B>
(2) Persons can be added to U<A, B>
Fulfilling both (1) and (2) is impossible, which can be proven using a indirect proof:
Assume fulfilling both conditions was possible.
The signature of add is add(TElement element) method and TElement extends IAggregable<TElement, TResult>.
From (1) and Car implements IAggregable<Car, Integer> we can therefore deduce A=Car.
And from (2) and Person implements IAggregable<Person, Integer> we can therefore deduce A=Person.
Combining those 2 results we get Car=Person which is obviously wrong. This contradiction concludes the proof.
This means you have to modify the restrictions on the type parameters or use the raw type.

Map with enum key and different value types

I want to define map in Java, which keys are enums, and types of value depend of key. For example, suppose that we have following enum type:
enum KeyType {
HEIGHT(Integer.class),
NAME(String.class),
WEIGHT(Double.class)
// constructor and getter for Class field
}
and some map:
Map< KeyType, Object > map = new EnumMap<>(KeyType.class);
Is there any simple and safe way to write generic method:
public < T > T get(KeyType key) {
//...
}
that would get value from that map and cast it to corresponding with type class?
UPDATE!!!:
With this in mind:
enum KeyType {
//your enums ...
private final Class val;
//constructor ...
//and generic(!) access to the class field:
<T> Class<T> val() {
return val;
}
}
...this is possible:
public <T> T get(KeyType key) {
return (T) key.val().cast(map.get(key));
}
Your map definition would need to be
Map< KeyType, ?> map = new EnumMap<>(KeyType.class);
If you specify Object as a generic type, only actual instances of Object are allowed, not sub-types.
I don't believe there's any straight forward, generic way (no pun intended) to do what you want. You would need to create some mapping function that translates the object to the correct type based on the enum.
You can't do it with enums. But you could write a "fake" enum (the way Java code did it before Java 1.5, with private constructors and public static instances), and attach a generic type to each constant:
import java.io.Serializable;
import java.util.Map;
public final class KeyType<T>
implements Serializable {
private static final long serialVersionUID = 1;
public static final KeyType<Integer> HEIGHT =
new KeyType<>("HEIGHT", Integer.class);
public static final KeyType<String> NAME =
new KeyType<>("NAME", String.class);
public static final KeyType<Double> WEIGHT =
new KeyType<>("WEIGHT", Double.class);
private static final KeyType<?>[] allValues = {
HEIGHT, NAME, WEIGHT
};
/** #serial */
private final String name;
/** #serial */
private final Class<T> type;
private KeyType(String name,
Class<T> type) {
this.name = name;
this.type = type;
}
public String name() {
return name;
}
public Class<T> getType() {
return type;
}
#Override
public String toString() {
return name();
}
public static KeyType<?>[] values() {
return allValues.clone();
}
public static KeyType<?> valueOf(String name) {
for (KeyType<?> value : allValues) {
if (value.name.equals(name)) {
return value;
}
}
throw new IllegalArgumentException("No such value: \"" + name + "\"");
}
#Override
public boolean equals(Object obj) {
return (obj instanceof KeyType &&
this.name.equals(((KeyType<?>) obj).name));
}
#Override
public int hashCode() {
return name.hashCode();
}
public T getValue(Map<KeyType<?>, ?> map) {
return type.cast(map.get(this));
}
}

OOP: inheritance with extends

Can anybody tell me why this code isn't correct?
public class Boss extends Angestellter {
Boss(String v, String n, int a) { // ERROR **
vorname = großKleinSchreibung(v);
nachname = großKleinSchreibung(n);
alter = a;
}
}
** Implicit super constructor Angestellter() is undefined. Must explicitly invoke another constructor
public class Angestellter {
protected String vorname;
protected String nachname;
public int alter;
Angestellter(String v, String n, int a) {
this.vorname = großKleinSchreibung(v);
this.nachname = großKleinSchreibung(n);
this.alter = a;
}
I dont find the error, because its exactly how its explained in the book which im using to learn oop with java.
You should call the constructor of the base class explicitly, since if you don't, the compiler adds an implicit call to the parameterless constructor of the base class, which doesn't exist in your case.
public class Boss extends Angestellter {
Boss(String v, String n, int a) {
super (v,n,a);
vorname = großKleinSchreibung(v);
nachname = großKleinSchreibung(n);
alter = a;
}
}
In simple words
You cannot override constructor of super class in JAVA
Here is your little modified code !!
public class Angestellter {
protected String vorname;
protected String nachname;
public int alter;
Angestellter(String v, String n, int a) {
this.vorname = großKleinSchreibung(v);
this.nachname = großKleinSchreibung(n);
this.alter = a;
}
...
}
public class Boss extends Angestellter {
... Other methods
}
// In main
Angestellter myObj = new Boss("asd","as",1); // It will call constructor itself ... because it is inherited !!

Categories

Resources