Guillermo Alvarez
Guillermo Alvarez

Reputation: 1775

Trying to understand Generics in java

I am modifying a sample class from a book and trying to convert it to use generics to help me learn how it works. You can see my code below where I made an attempt. The generic A, B, and C used to be String String and int.

public class Student<A,B,C> implements Person {
    A id;
    B name;
    C age;

    public Student(A i, B n, C a) {
        id = i;
        name = n;
        age = a;
    }

    protected int studyHours() {return age/2;}
    public A getID() {return id;}
    public B getName() {return name;}
    public C getAge() {return age;}
    public boolean equals(Person other) {
        if(!(other instanceof Student)) return false;
        Student s = (Student) other;
        return id.equals(s.id);
    }
    public String toString() {
        return "Student(ID: " + id + ", Name: " + name + ", Age: " + age + ")";
    }
    public static void main(String[] var0) {
        Student<String,String,int> studentOne = new Student("123", "Guillermo", 34);
        Student<String,String,int> studentTwo = new Student("345", "Cheryl", 35);
        int numberOfStudyHours;

        numberOfStudyHours = studentOne.studyHours();
        System.out.println("Guillermo studies " +numberOfStudyHours+ " hours");

    }
}

The Person Interface is below

public interface Person {
    public boolean equals(Person other);        //is this the same person?
    public String getName();
    public int getAge();
}

Your expert guidance would be greatly appreciated. I am getting this error:

 Student.java:4: error: Student is not abstract and does not override abstract method getAge() in Person
        public class Student<A,B,C> implements Person {
               ^
    Student.java:18: error: getAge() in Student cannot implement getAge() in Person
            public C getAge() {return age;}
                     ^
      return type C is not compatible with int
      where C is a type-variable:
        C extends Object declared in class Student
    Student.java:17: error: getName() in Student cannot implement getName() in Person
            public B getName() {return name;}
                     ^
      return type B is not compatible with String
      where B is a type-variable:
        B extends Object declared in class Student
    Student.java:15: error: bad operand types for binary operator '/'
            protected int studyHours() {return age/2;}
                                                  ^
      first type:  C
      second type: int
      where C is a type-variable:
        C extends Object declared in class Student
    Student.java:28: error: unexpected type
                Student<String,String,int> studentOne = new Student("123", "Guillermo", 34);
                                      ^
      required: reference
      found:    int
    Student.java:29: error: unexpected type
                Student<String,String,int> studentTwo = new Student("345", "Cheryl", 35);
                                      ^
      required: reference
      found:    int

Upvotes: 2

Views: 221

Answers (2)

Joshua Goldberg
Joshua Goldberg

Reputation: 5353

For some better examples of where generics make sense, look through the various Java Collections classes. For instance, it can make sense to make a Map from anything to anything else (String to Integer, Integer to String, Integer to Integer, Person to String). You want only one class to implement all those maps, but by instantiating each map with its types,

Map<Person,Person> motherMap = new HashMap<>();

the compiler and IDE know what kind of key has to be given to the get() method, and what type the result will be, preventing a lot of coding errors at the get-go.

Another place to look for examples where generics are used to good effect is the google libraries: see GuavaExplained.

For a practice exercise, you could try implementing a binary tree with left and right child nodes, where the tree nodes are all of the same generic type T.

For the compilation error, Generics cannot be used for primitive types—the lowercase ones like boolean and int—though you can use Boolean and Integer instead. Also, the interface would typically be generic as well: HashMap<K,V> implements Map<K,V>

Upvotes: 1

Christian Wilkie
Christian Wilkie

Reputation: 3823

For your example it looks like you should change your interface to:

public interface Person<B,C> {
    public boolean equals(Person other);        //is this the same person?
    public B getName();
    public C getAge();
}

and then

public class Student<A,B,C> implements Person<B,C> {
    A id;
    B name;
    C age;
     ...
}

But this isn't really a good use of generics. Also keep in mind you can't use int or other primitives with generics. You have to use Integer or the other boxing classes.

Upvotes: 0

Related Questions