JAVA generics constructor issue - java

I'm studying JAVA generics nowadays and find out some weird situation.
class A{
public void mInA(){
System.out.println("mInA");
}
}
interface I{
public void mInInterfaceI();
}
class B extends A implements I{
public void mInInterfaceI(){
System.out.println("mInterfaceI");
}
}
class MyList <TP1, TP2>{
MyList(TP1 data1){
this.data1 = data1;
}
TP1 data1;
TP2 data2;
MyList<TP1, TP2> next;
}
public class GenericPrepare {
public static void main(String[] args){
B obj = new B();
MyList<A,B> anchor = new MyList<>(obj);//Curious
anchor.data2 = new B();
anchor.next = null;
}
}
My constructor is designed to put TP1 as input. So I must input 'A' type reference as argument in above remark.
But when i input 'B' type reference as argument, JAVA is not complaining about it.
I have no idea what's going on here.

The MyList<A,B> constructor expects an A object as parameter, but because B extends A, B is actually assignable to A -> your code works.

Related

Implement a common function accepting argument of two different classes?

I have two classes A and B and they both have a common field in them, and I want to create a function in which if I pass Class A object then I want to set that common field value to the passed value and if I pass Class B object then I want to set that common field value to the passed value. Can anyone please tell me how can I do this, I am new to Java Generic Classes.
Otherwise I would have to make two different functions OR I would have to make an if and else which would decide that passed object belongs to which class ??
Class A
public class A{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class B
public class B{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class D
public class D{
public void change_footer(T generic_param, int value) {
generic_param.setFooter(value);
}
}
Class HelloWorld
public class HelloWorld{
public static void main(String []args){
Here I want to call
A a = new A();
new D().change_footer(a, 5);
B b = new B();
new D().change_footer(b, 5)
}
}
Thank You
And if I got all of the question wrong, and nor A nor B are generic, AND the type of field is fixed.
then you mean something like:
class D {
/*public <T extends Super> would be muuuch nicer here as well!*/
public /*static*/ <T> void change_footer(T obj, int data) {
//otherwise, you could just cast to Super...and set dat field.
if (obj instanceof A) {
((A) obj).setField(data);
} else if (obj instanceof B) {
((B) obj).setField(data);
} // else ... ?
}
}
Original answer:
Easy peasy (the "straight forward" implementation produces the desired results.):
class A<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
class B<T> extends A {//empty
}
class Test {
public static void main(String... args) {
B<Object> testB1 = new B<>(); //
testB1.setField(new Object());
System.out.println(testB1.getField());
B<String> testB2 = new B<>();
testB2.setField("blah blah");
System.out.println(testB2.getField());
B<Integer> testB3 = new B<>();
testB3.setField(42);
System.out.println(testB3.getField());
}
}
System.out:
java.lang.Object#6d06d69c
blah blah
42
It get's (little) more complicated, when you want to instantiate Ts ...but still possible/other question. :)
Edit to your comment:
If there's only one common field, then why not:
/*abstract */class Super<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
? ...and:
class A<T> extends Super { ... }
class B<T> extends Super { ... }

Generic Method with object as argument in Java

There are two classes A and B which have similar methods. How to write a generic method that takes either one of the class object as argument and will be able to call the methods of that class.
Edit : I do not have control over class A, B. I get them only as arguments. So i cannot modify add them.
public class methods {
public static void main(String[] args) {
new methods().getName(new B());
new methods().getName(new A());
}
private <T> void getName(T obj){
// obj.getName()
}
}
class A {
String name = "ClassA";
public void getName(){
System.out.println(name);
}
}
class B {
String name = "ClassB";
public void getName(){
System.out.println(name);
}
}
If the two classes do not implement a common interface, you could use reflection, but this is not type safe (you won't get any compilation errors if A or B no longer support getName() and reflection is much slower than calling a method directly.
You could also implement two adapters that share an interface and use those (with generics):
interface Wrapper {
String getName();
}
class WrapperA implements Wrapper {
final private A a;
public WrapperA(A wrapped) {
this.a = wrapped;
}
#Override public String getName() {
return a.getName();
}
}
Below solution uses instanceof operator in the generic method to reach your output.
public static void main(String[] args){
new methods().getName(new B());
new methods().getName(new A());
}
private <T> void getName(T obj) {
if(obj instanceof B){
((B) obj).getName();
}
else{
((A) obj).getName();
}
}

Why couldn't I deal with argument in java?

I'm java virgin. I've made really simple code like below.
class TreeData implements Comparable<TreeData> {
private String sixString;
private ArrayList<Integer> stringNum = new ArrayList<Integer>();
private ArrayList<Integer> charNum = new ArrayList<Integer>();
public TreeData(String sixString, int stringNum, int charNum){
this.sixString = sixString;
(this.stringNum).add(stringNum);
(this.charNum).add(charNum);
}
public int compareTo(TreeData other) {
return sixString.compareTo(other.getSixString());
}
public String getSixString(){
return sixString;
}
}
class Child<T extends Comparable<T>>{
public void print(T data){
//error : String a = data.getSixString();
System.out.println("hi");
}
}
public class Test {
public static void main(String[] args) {
Child<TreeData> child = new Child<TreeData>();
TreeData td = new TreeData("sixString", 8, 2);
child.print(td);
}
}
I had a problem in 'print' method in the Child class. When I tried calling the getSixString() method of data(passed as argument), it occurs error. I don't know why I can't using public method in the argument 'data'. Is it related with Generic? Thanks, in advance.
In your Child class, you only define T to be extending Comparable. Yet you expect it to have the method getSixString which Comparable doesn't have. What you probably want it for it to be extending TreeData:
class Child<T extends TreeData>{
public void print(T data){
String a = data.getSixString();
//should work now since T defines getSixString()
}
}
Or better yet if all you want is for T to be TreeData, you don't need any generic class. I'm assuming your real intention was:
class Child extends TreeData {
public void print(){
String a = getSixString();
}
}

covariant return or generic

I want to have a method in an interface that returns a class whose type is not defined in the package. The implementing class will then return a specific type. I can see at least 3 methods how I can do this, shown below as fn1, fn2 and fn3. In all cases there is some form of unchecked cast. Is any of these methods preferred? or is there something better? (assume that the interface I1 and the method dostuff are in some other jar package and do not have access to the Test or the Integer class)
public class Myclass {
public interface I1
{
Object fn1();
<T> T fn2();
<T> T fn3();
}
public class Test implements I1
{
#Override
public Integer fn1() {
return new Integer(1);
}
#Override
public <T> T fn2() {
return (T) new Integer(2); //requires cast to T
}
#Override
public Integer fn3() { //automatic unchecked conversion to T in return value
return new Integer(3);
}
}
public static void main(String[] args) {
Myclass c = new Myclass();
I1 t = c.new Test();
Integer i = (Integer) t.fn1(); //cast required here since I1.fn1() returns Object
Integer j = t.fn2();
Integer k = t.fn3();
dostuff(t);
}
static void dostuff(I1 p)
{
Object i = p.fn1();
Object j = p.fn2();
Object k = p.fn3();
}
}
Can't you use generics with the Interface? Like
public interface I1<T> {
T fn1();
// etc
}
Then there's no casting required when you refer to T.
That's what I prefer, at least. You can then also of course specify what you want T to be using
<T extends myInterface>
I would do it this way
public interface I1<T> {
T fn1();
}
public class Test implements I1<Integer> {
#Override
public Integer fn1() {
return new Integer(1);
}
}
public static void main(String[] args) {
Myclass c = new Myclass();
I1<Integer> t = c.new Test();
Integer i = t.fn1(); <-- no cast
}

Inheritance in Java

Consider the following code in Python:
class A(object):
CLASS_ATTRIBUTE = 42
def f(self):
return "CLASS_ATTRIBUTE: %d" % self.CLASS_ATTRIBUTE
class B(A):
CLASS_ATTRIBUTE = 44
Now A().f() and B().f() return "CLASS_ATTRIBUTE: 42" and "CLASS_ATTRIBUTE: 44" respectively.
How can I achieve a similar effect in Java? I want a CLASS_ATTRIBUTE field to be initialized statically and redefined in the inherited class but the f method should be only defined in the base class.
Is there a particular reason you want the attribute to be static? In Java the typical way you'd do this is to have A contain a protected variable that you then set in the constructors of the 2 classes:
public class A
{
protected int CLASS_ATTRIBUTE;
public A()
{
CLASS_ATTRIBUTE = 42;
}
public String f()
{
return "CLASS_ATTRIBUTE: " + CLASS_ATTRIBUTE;
}
}
public class B extends A
{
public B()
{
CLASS_ATTRIBUTE = 44;
}
}
Alternatively (and probably more consistent with Java design patterns) you'd declare a function that you can override to return the value instead of using a member variable.
Short answer: you cant solve it like this in Java. You'll have to solve it in another way.
In Java you can't override or "redeclare" fields in subclasses, and you can't override static methods.
It can be solved using an ugly reflection-hack (should be avoided though):
public class Main {
public static void main(String... args) {
A a = new A();
B b = new B();
System.out.println(a.f()); // Prints 42.
System.out.println(a.fReflection()); // Prints 42.
System.out.println(b.f()); // Prints 42.
System.out.println(b.fReflection()); // Prints 44.
}
}
class A {
static int CLASS_ATTRIBUTE = 42;
public int f() {
return CLASS_ATTRIBUTE;
}
public int fReflection() {
try {
return getClass().getDeclaredField("CLASS_ATTRIBUTE").getInt(null);
} catch (Exception wontHappen) {
return -1;
}
}
}
class B extends A {
// Compiles, but will not "override" A.CLASS_ATTRIBUTE.
static int CLASS_ATTRIBUTE = 44;
}
You can't do this directly with only a variable, because in Java variables cannot override (they only shadow the super classes variables).
You need to use a protected "getter" method, which can then be overridden by the subclass:
class A
{
private int attribute=42;
...
protected int getAttribute() {
return attribute;
}
}
class B
extends A
{
private int attribute=44;
...
protected int getAttribute() {
return attribute;
}
}
But note there's a special consideration to calling methods from an object's constructor, in that it allows object code to run before object construction is complete.
I'm not sure if you meant "statically" literally or not, but here's a brief example of how inheritance at it's most basic form looks in Java. Note that using a getter method to access the variable is a better idea for several reasons -- this is just an example.
public class Dog {
protected String whatISay = "Woof!";
public void speak(){
System.out.println(whatISay);
}
}
public class Poodle extends Dog {
public Poodle(){
whatISay = "Yap!";
}
}
public class Main {
public static void main(String[] args){
Poodle fluffy = new Poodle();
fluffy.speak();
Dog dog = new Dog();
dog.speak();
}
}
Yap!
Woof!
This way of doing it introduces as little intrusion as I could think of. setAttribute() could be named something like setDefaultValue() if that's clearer.
public class A
{
protected int attribute;
public A()
{
setAttribute();
}
public String f()
{
return "CLASS_ATTRIBUTE: " + attribute;
}
protected void setAttribute()
{
attribute = 42;
}
}
public class B extends A
{
#Override
protected void setAttribute()
{
attribute = 44;
}
}
public class Main
{
public static void main(String[] args)
{
A a = new A();
B b = new B();
System.out.println("A: " + a.f());
System.out.println("B: " + b.f());
}
}

Categories

Resources