Since I don't know how to phrase my question so that I get a helping result just by searching via Google I decided to ask here. I'm just searching for a way to tell a method that it should take every Object extending a certain class. Here are the things I tried so far:
public void method( Object<? extends Component> obj );
public void method( Component c );
The problem with the second one is that i have to cast every instance to Component again before method() accepts it and the first one just didn't work for me. Can anyone give me a quick solution?
The problem with the second one is that i have to cast every instance
to Component again before method() accepts it
No, you don't have to cast anything, that's how polymorphism works.
For example:
class A {
}
class B extends A {
}
class C extends B {
}
public class Main {
private void method(final A a) {
}
public static void main(final String[] args) {
final Main main = new Main();
main.method(new B());
main.method(new C());
}
}
If you're looking to define a method that takes subtypes of Component, use public <T extends Component> void method(T t){your code here}. This will work for any object, i.e. Component can be replaced with any other class that has subclasses.
The second form public void method( Component c ); is correct, If you need to typecast then you are trying to pass as parameter a variable which type is not Component or a subclass of Component. I don't know why.
Declaring variables with type Object is not usually the right thing to do, you should define them with the correct type when you know it.
Typecast is the way to tell the compiler you know the type of the object pointed by a reference when that reference does not have that type for any reason.
Related
I have a class BaseClass and it has two subclasses C and D. I need to put objects of both C and D type into the array of BaseClass. The assignment works.
But if I call a method print() defined in C and D on the array it will not compile. I am missing something but search on the web or here did not answer my question.
My book says the chain of inheritance will do look for print() in C.
If print() found in C use it. If not found in C go up to parent class.
How to fix?
According to the Java description the inheritance allows a subclass to inherit data and methods from the super class. Furthermore, in the inheritance it says that when a method is invoked on an object the JVM it will first look for the method in the class of the object. If the method is in there it will then use that method. However this following will not compile. The objective is to have an array of the superclass and assign to it objects of the subclasses.
The following is the program.
//This is an example program.
public class Tester
{
static public void main(String[] args)
{
BaseClass[] myarr = new BaseClass[10];
myarr[0] = new C();
myarr[1] = new D();
myarr[0].print(); //error
for (int i =0 ; i < 10; i++)
{
if(myarr[i] != null) myarr[i].print(); //will not compile. Why?
}
}
}
This is the superclass code.
public class BaseClass
{
public BaseClass()
{
}
//it wants print(), why?
}
Next I have two subclasses C and D.
//subclass
public class C extends BaseClass
{
public C()
{
}
public void print()
{
System.out.println(“hello C”);
}
}
And subclass D.
//subclass
public class D extends BaseClass
{
public D()
{
}
public void print()
{
System.out.println(“hello D”);
}
}
It does not work because when creating an Array of Type BaseClass, the compiler does not know anything about a print() method. These just get introduced in your 2 subclasses.
Just imagine you had an other Subclass called E (also extending Baseclass) which did not have a print() function. Now assign an object of E to one of the places in myarr. Until here everything would work fine. Now when you try calling the print() method the compiler would not know what to do. This is why the compiler cannot find print() and does not want to 'interprete' your code.
Now to solve this there are 2 possibilities. If you want a print()-method in every Subclass you could simply create one abstract method:
public abstract class BaseClass {
public BaseClass() {
// Some Constructor Work
}
// This tells the compiler there is a print()-method in every subclass because it must be overridden
public abstract void print();
}
Now in your Subclasses (I just do one for proof of concept :)):
public class SubClass extends BaseClass {
public SubClass() {
// Do Constructor Work if necessary
}
// I would highly suggest you also use this annotation because it helps you
// identifying overridden methods (but it is not obligatory to use)
#Override
public void print() {
System.out.println("Hello from SubClass");
}
}
Now in your main:
public static void main(String[] args) {
// Init Array
BaseClass[] myarr = new BaseClass[4];
myarr[0] = new SubClass();
myarr[1] = new OtherSubClass();
// and so on... I think you get the gist
// Now execute print()
myarr[0].print(); // This works perfectly now.
}
Now possibility 2 which depending on your usecase could be the only working one (though I would highly recommend to use the technique shown before as here you must be 100% certain which ClassType your object is) is a lot unsafer and you must know what you are doing or you get errors (and noone likes errors right? :)): Use Casting.
public static void main(String[] args) { // Note I will be using "your" classes here again
// Array Init...
BaseClass[] myarr = new BaseClass[10];
// Assign blabla
myarr[0] = new C();
myarr[1] = new D();
((C) myarr[0]).print(); // Casting to C-Type which has a print()
}
This will basically tell the compiler (and the JVM): "Hey don't care about what type this object is. Just assume it would be a C-Type!"
I think you start to realize what could be the problem. If the compiler wants to read a C-Type but instead gets a D-Type or an E-Type it does not know what to do --> Error.
Hope I could help you :)
EDIT:
Ah and note that by adding the abstract modifier to a class you cannot create an object of this class any more, just of the corresponding children-classes. This is why I also wanted to give you possibility 2 as this is more versatile.
At compile time, the compiler will check to see that BaseClass has a print() method since the static type of any element in myarr is BaseClass. At runtime, the program will be able to dynamically resolve the type of each object to either C or D. Only then will it look at the C or D classes for their respective print methods. To fix this, you could add a default print method in BaseClass.
I have seen in Java that one can make a Class generic and a method generic. I have also seen codes that make the constructor generic along with the Class. Can I make only the constructor generic? And if yes, how to call the constructor?
Yes you can.
class Example {
public <T> Example(T t) {}
public static void main(String[] args){
// In this example the type can be inferred, so new Example("foo")
// works, but here is the syntax just to show you the general case.
Example example = new<String>Example("foo");
}
}
I have lost in the Jungle of Generics, please help me :) I have something like this:
public class BaseClass<TYPE> {
public BaseClass(Class<TYPE> clazz) {};
}
public class FirstLevelClass<REFRESHABLE
extends RefreshableInterface> extends BaseClass<REFRESHABLE> {
public FirstLevelClass(Class<REFRESHABLE> clazz) {
super(clazz);
};
}
public class Argument<T extends AnyOtherClass>
implements RefreshableInterface {
public refresh() {}
}
pulbic class ProblematicClass
extends FirstLevelClass<Argument<AnyOtherClassDescendant>> {
public ProblematicClass() {
//Compiler error: Constructor
//FirstLevelClass<Argument<AnyOtherClassDescendant>>(Class<Argument>) is undefined
super(Argument.class);
}
}
As far as I think, the compiler should accept Argument since it implements RefreshableInterface.
Why do I get this error?
How can I make the ProblematicClass working?
ps: if you have better title for this, please change it. I could not make up better.
Issue is, your constructor expects a Class<T>, and T in your code is inferred as Argument<AnyOtherClassDescendant>.
So, you should pass a Class<Argument<AnyOtherClassDescendant>>, and you're passing Class<Argument>. But you can't pass that Class instance directly, as you cannot do Argument<AnyOtherClassDescendant>.class.
You can however, solve the issue by typecasting the class to required instance:
public ProblematicClass() {
super((Class<Argument<AnyOtherClassDescendant>>)(Class<?>)Argument.class);
}
Note, how you've to typecast Class<Argument> first to Class<?>, and then the resultant type to Class<Argument<AnyOtherClassDescendant>>. There is no simple way to achieve that.
The reason behind this is, there is only a single Class instance for all parameterized instantiation of a generic type, that is associated with the class itself. A single compilation unit of a generic type, compiles to just a single class file. I guess this is different in how C++ implements templates. There you get different machine codes for different instantiation.
So, if you execute the below code, you'll get true as output:
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
boolean isSameClassInstance = strList.getClass() == intList.getClass();
System.out.println(isSameClassInstance);
This is a very basic question, but I'd quite like an explanation of why my question can or cannot be achieved.
If I have a class (A) which contains say a string, with a set method for that string. And I instantiate another class (B) from the first class (A), why can't I then access the first class (A) from the new class (B) to call the set method for the string in the first class (A).
The only reason I ask is that I'm working on a project with a similar problem, from a main class I create a new class which returns some buttons. And when a button is clicked the ActionListener in the main class is supposed to change the String in the initial class, but I cannot seem to access the set Method of the original class without re-instantiating the class.
Sorry if that sounds rambled, but I really want to understand why this is an issue, and what the correct way of doing it is. I know I'll probably be shot down on this, but any help is appreciated.
Because class B needs to hold a reference of the instance of A from which it has been created. There is no formal reason for which this should be made by default. For example:
public class B {
private final A creator;
public B(A creator) {
// you might want to check for non null A
this.creator = creator;
}
public void foo(String value) {
creator.setText(value);
}
}
Don't know if its the most elegant solution, but if you want object of class B to have a reference to object of class A (the creator) you can use Alessandro example code for class(B) and something like this in class A:
public class A
{
private String text;
public void createB()
{
new B(this);
}
public void setText(String b)
{
text = b;
}
}
Class cannot be called unless its been referenced by an Object. So you have to create something like this in Class B
myobject = FirstClass.new //I am not sure about java syntax as its been many years.
then you can call all the methods of FirstClass on this object and use them in SecondClass.
If B extends A, you can invoke the public methods in B that pertain to A.
If B doesn't extend A, it has no knowledge of A's methods. This is just how Java's inheritance works.
public class A
{ }
public class B extends A
{
public void add()
{
System.out.println("add in B");
}
}
Now here if we call add in following way hen it gives an error:
A a1 = new B;
a1.add();
But when we add the add() method in class A and then call in the similar fashion then add() method of child class is called.
i.e.
public class A
{
public void add()
{
System.out.println("add in A");
}
}
public class B extends A
{
public void add()
{
System.out.println("add in B");
}
}
call:
A a1 = new B;
a1.add();
output:
add in B
Why is it so?
at the method invocation of a1.add() the compiler checks if the method is present. But it only knows that a1 is a reference to an object of class A, which does not have that method. So the compilation fails.
In this trivial example it would probably be easy for the compiler to deduct the correct type. But in more general cases it wouldn't. And therefore this kind of logic is not part of the specs.
Because java does not know at compile time that a1 will refer to an instance of B at runtime. It only knows the declared type, so it only allows calls that work with the declared type.
When the Java compiler looks at the reference a1, it knows what methods are available. In your first example, class A does not have add() in its API. It is legal in this case to perform a cast of a1 to B like so:
((B)a1).add();
and the compiler will not complain.
You want to call a method on an object of declared type A but implement it only in a subclass B of A.
In this situation you would normally make A an abstract class and declare add() an abstract method in A.
Good answers...I had a doubt too regarding this but now I am clear :)
And one more thing ..you don't have to go into the trouble of declaring an abstract method,just make an empty method with the same name and signature in your parent class and " voila " all compilation errors are gone ;)
In your case you can add a void add(){} method like this and you wont have any problems