I have an object object and I'm going to call it's method toString. How do I know in what exact class this method is implemented last?
For example if we have hierarchy:
class A /*extends Object */{
}
class B extends A{
public String toString() {
return "representation";
}
}
class C extends B{
}
class D extends C{
}
and the object
Object object = new SomeClass(); //(A/B/C/D/Object)
then for toString() I should get Object for Object and A but B for B, C and D
You can use the Method.getDeclaringClass() method:
...
private Class<?> definingClass(Class<?> clz, String method) throws NoSuchMethodException, SecurityException {
Method m = clz.getMethod(method);
return m.getDeclaringClass();
}
...
System.err.println(definingClass(A.class, "toString"));
System.err.println(definingClass(B.class, "toString"));
System.err.println(definingClass(C.class, "toString"));
System.err.println(definingClass(D.class, "toString"));
...
Result:
class java.lang.Object
class com.example.B
class com.example.B
class com.example.B
You need to extend the definingClass() method appropriately if you need to look up methods which have parameters.
Related
Here is a Java code structure:
public interface MyBaby<T> {...}
public class A implements MyBaby<Foo> {...}
public class B implements MyBaby<Boo> {...}
public Class Foo {...}
public Class Boo {...}
public class MyFactory {
...
public synchronized static MyFactory getInstance() {...}
public MyBaby<?> getMyBaby(BabyType type) {...}
}
The above code structure is working with a little problem. To have an instance, I need to do a down casting such as
MyBaby<Foo> baby = (MyBaby<Foo>) MyBabyFactory.getInstance().getMyBaby(BabyType.CUTE);
How to change the code so that the down casting isn't needed?
You should pass a Class object like this.
public <T> MyBaby<T> getMyBaby(Class<T> type) {
return (MyBaby<T>) (type == Foo.class ? new A() : new B());
}
And
MyBaby<Foo> a = MyFactory.getInstance().getMyBaby(Foo.class); // OK
MyBaby<Foo> b = MyFactory.getInstance().getMyBaby(Boo.class); // Compile error
I am in a situation as follows.
I have an interface A which is inherited by class B,C,D (B,C,D implements A).
public interface A{
public String someMethod();
}
class B implements A{
ObjectType1 model;
#Override
public String someMethod(){
if(model instanceof X){
System.out.print(true);
}
}
}
class C implements A{
ObjectType2 model;
#Override
public String someMethod(){
if(model instanceof X){
System.out.print(true);
}
}
class D implements A{
ObjectType3 model;
#Override
public String someMethod(){
if(model instanceof X){
System.out.print(true);
}
}
As you can see all method implementations are the same. So I am duplicating code. My plan was to move the method to A and make A an abstract class. But the problem is my method depends on the model field. So what would be my options to make this code better?
bdw class A,B,C extends and implements other classes too.
EDIT
modification in code. check field
I don't see any problem related to the model field transforming the interface A into an abstract class.
There is no need to reimplement the method in the subclasses if it is the same, unless you want to change its behavior (override it).
public abstract class A {
// Make it protected so it can accessible by subclasses
protected Object model;
// Common behavior that will be inherited by subclasses
public String someMethod() {
if (model instanceof X) {
return "x";
} else {
return "not x";
}
}
}
public class B extends A {
// Subclasses may access superclasses fields if protected or public.
public void someOtherMethod() {
System.out.println(super.model.toString());
}
}
public class C extends A {
// You may wish to override a parent's method behavior
#Override
public String someMethod() {
return "subclass implements it different";
}
}
For your new code example, if you really want to do that in a procedural way you can create an abstract superclass ObjectType and then it will be accessible for the parent as well.
However I wouldn't do that. It seems to me that in doing so is the very opposite of what object orientation tries to solve.
By using a subclass to define the behavior, you wouldn't need to do it in a procedural logic. That's precisely then point of using objects, inheritance and overriding/implementing behavior as needed.
Create a parent class A with said field, and said function. Have the other classes extend A. No need to override them if they function the same.
To deduplicate, you can either make A an abstract class and move the implementation of the method and the field there, or create an abstract class, say E, that implements the interface with that method and field and then have B, C and D extend that class E.
For the more general question of depending on a subclass's field, you can create an abstract method getModel which the subclasses decide how to implement -- by returning a model field or doing something else.
If you are using java 8 you could use default method in interface A, with a getter method for model.
public interface A{
default public String someMethod() {
if(getModel() instanceof X){
System.out.print(true);
}
}
public Object model getModel();
}
Then implement getModel method in all child interfaces.
If you're going to do this you must have model to be of the same (basic) type in all derived objects. If it were of the same type there's a case for putting the model to a base class. Anyway if they are of different derived types you would need to have an accessor to get it.
interface B {
BaseModel getModel();
default public strict doSomething() {
BaseModel m = getModel();
// do something with m
}
}
class D implements B {
DerivedModel model;
public getModel() {
return model;
}
}
If I was given a chance to refactor it, I will follow below approach, leveraging Java 8 Default Methods:
interface A {
default String someMethod(X objectType) {
if (objectType instanceof X) {
System.out.println(true);
}
// return something, for now returning class
return objectType.getClass().toString();
}
}
class B implements A {
#Override
public String someMethod(X objectType) {
if (objectType instanceof X) {
System.out.println(true);
}
// return "Hello"
return "Hello";
}
}
class C implements A {}
class D implements A {}
Usage:
public class Main implements A {
public static void main(String[] args) {
B b = new B();
C c = new C();
D d = new D();
Main main = new Main();
main.call(b);
main.call(c);
main.call(d);
}
public void call(A clazz) {
ObjectType1 objectType1 = new ObjectType1();
String type = clazz.someMethod(objectType1);
System.out.println(type);
}
}
interface X {
}
class ObjectType1 implements X {
}
If I have following Java code:
package a.b.c;
public class A{
static class B{
public B(){
}
}
}
I want to change class B's modifier to "public" at run-time via reflection, how can I do that? Thanks.
So the after effect will be like following:
package a.b.c;
public class A{
public static class B{
public B(){
}
}
}
With reflection you cannot change the class modifiers but you can create objects of the specified class and invoke its methods.
You can get instance the class from the enclosing class with the method getDeclaredClasses(), and then modify the contructor and instantiate the object:
Class a = A.class;
Class subs[] = a.getDeclaredClasses();
Object o = null;
for (Class cls: subs) {
if(cls.getCanonicalName().equals("A.B")){
for (Constructor ct: cls.getDeclaredConstructors()) {
ct.setAccessible(true);
o = ct.newInstance(new Inner());
// o is an instance of B
// you can get public and private method and invoke them
for (Method m: o.getClass().getDeclaredMethods())
if(m.getName().equals("....")){
m.setAccessible(true);
m.invoke(o, ....));
}
}
}
}
Instead of the for loop you could get methods by name and list of parameters.
I have an A interface with a method getT(), abstract B class with method getS() and class C that extends B class which implements A interface. I'm overriding methods from A interface and B superclass inside the C subclass. Then in the main method I instantiate the C class to be typeo if A like this: A obj = new C(); I'am able to call the getT() from obj, but can't call getS() method. How can I call getS() method from obj, but I can't change the type of obj, it has to be A. Here is the code:
Interface A :
public interface A {
public String getT();
}
Abstract class B :
public abstract class B implements A {
public abstract String getS();
}
subclass C :
public class C extends B {
#Override
public String getT() {
System.out.println("method getT() from C class");
return null;
}
#Override
public String getS() {
return null;
}
}
And the main method inside of the T class :
public class T {
public static void main(String[] args) {
A obj = new C();
obj.getT();
}
}
With a reference variable of type A, you cannot call getS(), because it could be any type that implements A, say, AImplementer, that doesn't extend from B. Any A object doesn't necessarily have a getS() method. It's only guaranteed to have a getT() method.
If obj has to be a type A and you need to call getS(), then include the getS() method in the definition of the A interface:
public interface A {
public String getT();
public String getS(); // Add this line.
}
Then B is still an A, and you can call getS() on an A reference variable.
By the way, I don't see any static methods in your code. Static methods cannot be overridden.
To gain access to the method you will need to downcast obj to B.
So you could have:
((B)obj).getS();
Downcasting: http://www.programmerinterview.com/index.php/java-questions/downcasting-in-java/
the type class of obj is A, but A hasn't method getS() so you can't call in the main method.
obj must be class B or class C.
Good day,
I have the following problem:
class B extends class A and methods of both are called by another method in another class after instantiating class B (example follows):
public class A{
//fields
//constructors
//methods
}
public class B extends A{
//fields
//constructors
//methods
}
public class CALLER{
public A getA(enum E){
return Factory.getB(otherobject,E);
}
}
public class Factory{
public static B getB(object o,enum e){
//do something with enums and get B
b = new B();
//populate b
return b;
}
}
Class B does not override any method of class A.
Somehow at compile time this doesn't get any error but at runtime class CALLER excepts: java.lang.NoSuchMethodError: Factory.getB(object,enum) A
My question is: if B extends A why a method from a different class can't return A even if its return clause returns a B object directly?
In fact changing:
public static B getB(object, enum);
with
public static A getB(object, enum);
solves the exception but then I get another exception (classCast) because obviously in other parts of the code it is awaiting a B type object, not an A.
Thanks in advance.
You would get this exception if you had compiled CALLER.java with another version of Factory.java that would have getB returning A, then updated Factory.java so that getB returns B, then recompiled Factory.java but not CALLER.java
UPDATE:
Perhaps you want to do something like this:
public abstract class Factory {
public abstract A getInstance(object o, enum e);
}
public class FactoryB extends Factory {
#Override
public B getInstance(object o,enum e){
//do something with enums and get B
b = new B();
//populate b
return b;
}
}
But the factory would then need to be instanciated.
The first one looks like a reflection error. The java reflection classes look for the exact method signature "A getB(Object,Enum)" and not "B getB(Object,Enum)".
The second, as long as you actually create an object of type B in your getB(..) method, it will return this object. The classCast exception will only be thrown if you create a new A instead of a new B.