I have an abstract method in an abstract class, Student.
The Subclass, JUPASStudent overrides it.
Now I am trying to sort the ArrayList of type Student. It requires to call that abstract method but I am unable to do so.
I am writing here my partial code.
Superclass:
abstract class Student {
protected String name;
public Student (String name) {
this.name = name;
}
public String getName() {
return name;
}
abstract double getResult(); //abstract method
}
Subclass:
public class JUPASStudent extends Student {
private double dseResult;
public JUPASStudent(String n, double d) {
super (n);
this.dseResult = d;
}
public double getResult() {
return dseResult; //abstract method is overridden here
}
public String getName() {
return super.name;
}
public void setResult(double dseResult) {
this.dseResult = dseResult;
}
public void setName(String name) {
super.name = name;
}
}
Now I am writing a Sort function to make an ArrayList (Student class)
public ArrayList <Student> sort(ArrayList<Student> sList){
sList.sort(Comparator.comparingInt(Student::getResult));
return sList;
}
Input:
A 9
B 5
C 8
Expected Output:
B 5
C 8
A 9
Error
-The method comparingInt(ToIntFunction<? super T>) in the type Comparator is not applicable for the arguments (Student::getResult)
-The type Student does not define getResult(T) that is applicable here
If you have override the method in the subclass, it'll use the implementation of the subclass, so don't worry about calling it explicit, at least in your case
getResult() is returning double, try returning Int and i think it would work.
edit:
or use comparingDouble() method
Related
I have a basic inheritance situation with an overloaded method in the super class.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
The following Employee class extends the Person class above:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
The main method simply creates an Employee object (both static and dynamic type) and calls .work() on it:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
This ends up printing
This person is not an Employee
Looking through this I had thought that since both the static and dynamic type of the object e1 is Employee it would call the overloaded method in Person that takes an Employee as a parameter. Since I am clearly wrong about this I opened a debugger assuming the reference to "this" at the line getWorkDetail(this) in the Person class must have morphed to it's super class. However this is not what I found.
Clearly at this point in the code this is an Employee object, however it still chose to execute the overloaded method getWorkDetail(Person p). Can anyone explain this behavior?
Unlike method overrides, method overloads are linked based on the static type. And in this case, getWorkDetail(this) in Person only knows about the Person type.
Method overloading is not designed to provide dynamic runtime behavior.
To take advantage of dynamic binding, you may need to redesign your code to override the methods, instead:
public static void main(String[] args) throws IOException {
new Employee("Manager1", 1976, "Female").getWorkDetail();
new Person("Manager1", 1976, "Female").getWorkDetail();
}
And modify behavior based on implementing classes. Of course, you can overload methods, as long as you take care of overriding the overloaded methods too, if required.
class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex) {
name = theName;
dob = birth;
gender = sex;
}
public void getWorkDetail() {
System.out.println("This person is not an Employee");
}
}
class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex) {
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
public void getWorkDetail() {
System.out.println("This person is an Employee");
}
}
The overload resolution happens during compile time, not at runtime.
So, when you call getWorkDetails(this), this is assumed to be a Person (which is the static type) and hence called the corresponding overload.
Note: Using this inside Employee class would have made it an Employee type. You can verify this by overloading work() in Employee like this.
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
Problem specific solution
In some languages parameters are resolved to their dynamic type, but not in java. The compiler already determines at compile time where your getWorkDetail(this); will go. this is of type Person, so getWorkDetail(Person e) is called. In your specific case the solution is quite obvious. As others have already pointed out, you'll need to override getWorkDetail() in the Employee class.
Resolving methods to their dynamic parameter types
To solve the general problem of resolving parameter types at runtime, using the instanceof operator should be avoided, as it usually leads to unclean code.
If you have two different classes, a solution as simple as stated above is no longer possible. In these cases you'll have to use the visitor pattern.
Consider the following classes:
public interface Animal {
default void eat(Food food) {
food.eatenBy(this);
}
void eatMeat(Meat meat);
void eatVegetables(Vegetables vegetables);
}
public class Shark implements Animal {
public void eatMeat (Meat food) {
System.out.println("Tasty meat!");
}
public void eatVegetables (Vegetables food) {
System.out.println("Yuck!");
}
}
public interface Food {
void eatenBy(Animal animal);
}
public class Meat implements Food {
public void eatenBy(Animal animal) {
animal.eatMeat(this);
}
}
public class Vegetables implements Food {
public void eatenBy(Animal animal) {
animal.eatVegetables(this);
}
}
Which you can call like this:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
Following the visitor pattern calling Animal.eat will call Food.eatenBy, which is implemented by both Meat and Vegetables. Those classes will call the more specific eatMeat or eatVegetables method, which uses the correct (dynamic) types.
Call preference
class Foo {
static void test(int arg) { System.out.println("int"); }
static void test(float arg) { System.out.println("float"); }
static void test(Integer arg) { System.out.println("Integer"); }
static void test(int... arg) { System.out.println("int..."); }
public static void main(String[] arg) {
test(6);
}
}
The output will be int printed on console. Now you comment the first test() method and see what is the output coming.
This is the preference hirarchey in primitive data types. Now coming to derived types declare a class FooChild like this
class FooChild extends Foo {
}
and create two new methods in Foo like
static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }
then in main method try calling testChild like this testChild(new FooChild());.
getWorkDetail(this) does not know what the subclasses are. call getWorkDetail instead.
This is for learning. I have an interface that is implemented by 2 classes, and I am supposed to reduce the amount of code I use in order to keep things more clean and less messy. Currently, the code looks like this:
public abstract class VClass implements IntFace {
protected String name;
public VClass(String name) {
this.name = name;
}
public int value (SClass sc) {//comes from a diff class
return sc.lookup(name);
}
public String getName() {
return name;
}
#Override
public String toString() {
return getName();
}
}
public abstract class NClass extends VClass implements IntFace {
public Number(String name) {
super(name);
this.name = name;
}
public int value (SClass sc) {
return sc.lookup(name);
}
public String getName() {
return name;
}
#Override
public String toString() {
return getName();
}
}
public interface IntFace {
public int value (SClass sc);
public String toString (int num);
}
can this code be more condensed?
You can remove the following things from your code:
implements IntFace from NClass declaration. Since NClass extends VClass, it implements IntFace as well.
this.name = name; from NClass constructor. name is initialized in a superclass constructor
value and getName methods from NClass. These methods are implemented in a superclass.
public modifier from interface methods declaration. Methods in interfaces are public by default.
Now you can also make name field private since it's no longer used in a NClass.
I have a basic inheritance situation with an overloaded method in the super class.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
The following Employee class extends the Person class above:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
The main method simply creates an Employee object (both static and dynamic type) and calls .work() on it:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
This ends up printing
This person is not an Employee
Looking through this I had thought that since both the static and dynamic type of the object e1 is Employee it would call the overloaded method in Person that takes an Employee as a parameter. Since I am clearly wrong about this I opened a debugger assuming the reference to "this" at the line getWorkDetail(this) in the Person class must have morphed to it's super class. However this is not what I found.
Clearly at this point in the code this is an Employee object, however it still chose to execute the overloaded method getWorkDetail(Person p). Can anyone explain this behavior?
Unlike method overrides, method overloads are linked based on the static type. And in this case, getWorkDetail(this) in Person only knows about the Person type.
Method overloading is not designed to provide dynamic runtime behavior.
To take advantage of dynamic binding, you may need to redesign your code to override the methods, instead:
public static void main(String[] args) throws IOException {
new Employee("Manager1", 1976, "Female").getWorkDetail();
new Person("Manager1", 1976, "Female").getWorkDetail();
}
And modify behavior based on implementing classes. Of course, you can overload methods, as long as you take care of overriding the overloaded methods too, if required.
class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex) {
name = theName;
dob = birth;
gender = sex;
}
public void getWorkDetail() {
System.out.println("This person is not an Employee");
}
}
class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex) {
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
public void getWorkDetail() {
System.out.println("This person is an Employee");
}
}
The overload resolution happens during compile time, not at runtime.
So, when you call getWorkDetails(this), this is assumed to be a Person (which is the static type) and hence called the corresponding overload.
Note: Using this inside Employee class would have made it an Employee type. You can verify this by overloading work() in Employee like this.
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
Problem specific solution
In some languages parameters are resolved to their dynamic type, but not in java. The compiler already determines at compile time where your getWorkDetail(this); will go. this is of type Person, so getWorkDetail(Person e) is called. In your specific case the solution is quite obvious. As others have already pointed out, you'll need to override getWorkDetail() in the Employee class.
Resolving methods to their dynamic parameter types
To solve the general problem of resolving parameter types at runtime, using the instanceof operator should be avoided, as it usually leads to unclean code.
If you have two different classes, a solution as simple as stated above is no longer possible. In these cases you'll have to use the visitor pattern.
Consider the following classes:
public interface Animal {
default void eat(Food food) {
food.eatenBy(this);
}
void eatMeat(Meat meat);
void eatVegetables(Vegetables vegetables);
}
public class Shark implements Animal {
public void eatMeat (Meat food) {
System.out.println("Tasty meat!");
}
public void eatVegetables (Vegetables food) {
System.out.println("Yuck!");
}
}
public interface Food {
void eatenBy(Animal animal);
}
public class Meat implements Food {
public void eatenBy(Animal animal) {
animal.eatMeat(this);
}
}
public class Vegetables implements Food {
public void eatenBy(Animal animal) {
animal.eatVegetables(this);
}
}
Which you can call like this:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
Following the visitor pattern calling Animal.eat will call Food.eatenBy, which is implemented by both Meat and Vegetables. Those classes will call the more specific eatMeat or eatVegetables method, which uses the correct (dynamic) types.
Call preference
class Foo {
static void test(int arg) { System.out.println("int"); }
static void test(float arg) { System.out.println("float"); }
static void test(Integer arg) { System.out.println("Integer"); }
static void test(int... arg) { System.out.println("int..."); }
public static void main(String[] arg) {
test(6);
}
}
The output will be int printed on console. Now you comment the first test() method and see what is the output coming.
This is the preference hirarchey in primitive data types. Now coming to derived types declare a class FooChild like this
class FooChild extends Foo {
}
and create two new methods in Foo like
static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }
then in main method try calling testChild like this testChild(new FooChild());.
getWorkDetail(this) does not know what the subclasses are. call getWorkDetail instead.
I have following two classes:
public Class A{
String name;
Integer age;
//setters and getters
}
And
public Class B{
String name;
Integer age;
Integer height;
//setters and getters
}
and following method
public String getMyName(B b){
return b.getName()+" "+b.getAge()+" "+b.getHeight();
}
Is it possible to refactor this method to use generics which will allow me to call it for objects of those two different classes?
E.g
public <T> String getMyName(T t){
return t.getName()+" "+t.getAge()+( t instanceof B ? " "+t.getHeight() : "");
}
Of course it doesn't work since t doesn't know methods getName, getAge and getHeight.
Classes are not in any relation( I know that they can inherit from one common class and use <T extends C> but they don't have superclass or common interface)
No, without using a common interface or superclass this is not possible with generics. You could use reflection but I'd advice against that and suggest providing a common interface instead.
As others said, there would be other ways to handle that case (e.g. method overloading or passing Object and using instanceof and casts) but if you can use a common interface, I'd still go that way.
Note that Java generics are unlinke C++ generics/templates which would allow what you want to do - and there are good reasons for that difference.
This is the place where people shout the line Programming with interfaces.
Take a an interface and add common methods to it and create a generic method which takes that interface as a argument.
That makes your life easy.
You can use instanceof to check whether is compatible type and if it is, cast object to your type and call methods. It is not elegant way, but still. So this way, you can use your method as generic. :)
You can dynamically adapt them on the fly - something like:
public class A {
String name;
Integer age;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
public class B {
String name;
Integer age;
Integer height;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Integer getHeight() {
return height;
}
}
// Create a common interface.
public interface AorB {
public String getName();
public Integer getAge();
// Use Java 8 to implant a default getHeight if it is missing.
default Integer getHeight() {
return 0;
}
}
// Dynamicaly adapt each type.
public String getMyName(A a) {
// Adapt it on the fly.
return getMyName(new AorB() {
#Override
public String getName() {
return a.getName();
}
#Override
public Integer getAge() {
return a.getAge();
}
});
}
public String getMyName(B b) {
// Adapt it on the fly.
return getMyName(new AorB() {
#Override
public String getName() {
return b.getName();
}
#Override
public Integer getAge() {
return b.getAge();
}
#Override
public Integer getHeight() {
return b.getHeight();
}
});
}
// Your method almost untouched.
public String getMyName(AorB ab) {
return ab.getName() + " " + ab.getAge() + " " + ab.getHeight();
}
public void test() {
A a = new A();
a.name = "A";
a.age = 10;
B b = new B();
b.name = "B";
b.age = 10;
b.height = 12;
System.out.println("A:" + getMyName(a));
System.out.println("B:" + getMyName(b));
}
I am using Java-8 default here to implement a default getHeight but it would not take much effort to eliminate that - you would need to implement a getHeight for the getMyName(A) method.
Sadly - of course - this is not using generics in the solution so you may see this as not an answer to your question but it is an alternate solution to your problem so I chose to post.
I have my Pet super class which then has a Dog subclass, and a particular method in my super class is getSpecies(). In my subclass I want to be able to return super.getSpecies(), but also return another variable (in this case, smell) inside that method as well.
Super class:
public class Pet {
protected int lifeSpan;
protected String species, name, interaction;
public Pet(){
}
public Pet(int lifeSpan, String species, String name){
this.lifeSpan = lifeSpan;
this.species = species;
this.name = name;
}
public final float costs(float cost){
return cost;
}
public void setSpecies(String species){
this.species = species;
}
public String getSpecies(){
return this.species;
}
}
Subclass "Dog":
public class Dog extends Pet{
protected String smell;
private String species;
public Dog(String smell){
super(15, "Dog", "Rex");
this.smell = smell;
}
public Dog(){
}
public void setSmell(String smell){
this.smell = smell;
}
public String getSpecies(){
super.getSpecies();
smell = "high"; //Meant to deliberately set it to "High". How am I to return this?
}
public String getSmell(){
return this.smell;
}
}
You cannot return two values in a single function. What you have to do is use your getter for the smell member variable instead.
public class Dog extends Pet{
protected String smell;
private String species;
public Dog(String smell){
super(15, "Dog", "Rex");
this.smell = smell;
}
public Dog(){
}
public void setSmell(String smell){
this.smell = smell;
}
public String getSpecies(){
super.getSpecies();
}
public String getSmell(){
return this.smell;
}
}
Then let's say you want both species and smell, you have to check if the pet is in fact a dog, and if it is, you can safely cast it as a dog and use the specific methods of the Dog class.
if ( pet instanceof Dog ) {
String species = pet.getSpecies();
String smell = (Dog)pet.getSmell();
}
First things first: When calling super.getSpecies() you should save or hand over it's return value somewhere. Then you might consider concatenating this return string an your second return value (high) like this:
public String getSpecies(){
return "high " + super.getSpecies();
}
But:
the return of that high dog doesn't make much sense IMO.
a getter is expected to return only one value, the one it's name comes from.
There is no ather way to return multiple values except for passing objects that take the results as arguements. But that solution would be far away from a simple getter.
You should consider (like Pilibobby pointed out in his comment below) using two different getters in your case, getSpecies() and getSmell(), and combine their results at the place you are calling them from.