Reputation: 438
I'm trying to use generics as abstraction layer similar as Java collections. Here is a simplified example: the class EmployeeRecord stores information about employee and class Table should be generic and able to store various type of data. The type is passed to Table
as generics.
I've problem with pass calls to the stored, specific class.
What's wrong with call of method print()? How do I solve it?
class EmployeeRecord
{
String name;
EmployeeRecord( String name )
{
this.name = name;
}
void print()
{
System.out.println( name );
}
}
class Table<Record>
{
Record rec;
void set( Record rec )
{
this.rec = rec;
}
void printAll()
{
rec.print(); // COMPILER ERROR
/*
Test.java:27: error: cannot find symbol
rec.print();
^
symbol: method print()
location: variable rec of type Record
where Record is a type-variable:
Record extends Object declared in class Table
1 error
*/
}
}
public class Test
{
public static void main( String[] argv )
{
EmployeeRecord emp = new EmployeeRecord("John");
Table<EmployeeRecord> tab = new Table<EmployeeRecord>();
tab.set( emp );
tab.printAll();
}
}
Upvotes: 0
Views: 265
Reputation: 51990
Java compiles generics using type erasure. If the type is not bound, the compiler treats instances of the parameterized type as being an Object
instance.
To solve that, you have to bind the type to some super-type having the desired method:
interface Record {
...
}
class Table<T extends Record> {
...
}
Once bound, the compiler know that you can call any method of Record
on an instance of type T
.
In addition, it will reject any attempt to instantiate a Table
with a parameterized type that is not a sub-class of Record
. Whereas, in your original code, your Table
object may be instantiated with any type parameter (which was probably not the desired behavior).
Upvotes: 0
Reputation: 2394
One way to achieve this is to create common interface which all your record classes is going to implement
interface Record{
void print();
}
Then your EmployeeRecord
class will look like this
class EmployeeRecord implements Record
{
String name;
EmployeeRecord( String name )
{
this.name = name;
}
@Override
public void print()
{
System.out.println( name );
}
}
And your Table will look like this
class Table<T extends Record>
{
T rec;
void set( T rec )
{
this.rec = rec;
}
void printAll()
{
rec.print();
}
}
Then you call this from main method like this
public class Test {
public static void main(String[] args) {
EmployeeRecord emp = new EmployeeRecord("John");
Table<EmployeeRecord> tab = new Table<EmployeeRecord>();
tab.set( emp );
tab.printAll();
}
}
Upvotes: 1