Java using enums as method reference holders? - java

I'm going to try my best to explain my problem using a scenario:
I have ClassA which contains only one non-static instance of ClassB, many non-static methods that affect that instance of ClassB that we can call EFFECTS and one last non-static getter method that returns that instance of ClassB.
I have ClassC which contains a non-static array of instances of ClassB. In ClassC I have two non-static methods, one that gets a single instance of ClassB from the array and another that sets a single instance of ClassB by the given index value.
What I'm trying to do: I want to have a ClassD that you can create instances of and which acts like an List of EFFECTS, and ClassD would have a non-static method that takes in ClassC as a parameter. That method then applies all these EFFECTS stored in the instance of ClassD to every instance of ClassB stored in the Array of the ClassC parameter provided in this method. Finally this method returns the ClassC with changed ClassB values in its array.
My current solution but I don't know how to get it to work is create an Enum with method references as constants? And then be able to store these in ClassD? And somehow call them? But I'm not extremely familiar with enums, and I've searched online for this but can't find out how to make this work.
Example of Scenario:
public class ClassA {
ClassB classB;
public ClassB get() { return classB; }
public void effectA() {
//affects classB instance
}
public void effectB() {
//affects classB instance
}
public void effectC() {
//affects classB instance
}
}
public class ClassB {
//Code for ClassB
}
public class ClassC {
ClassB[] classBs;
public ClassC(int size) {
classBs = new ClassB[size];
}
public ClassB getB(int index) {
return classBs[index];
}
public void setB(int index, ClassB classB) {
classBs[index] = classB;
}
public int getSize() {
return classBs.length;
}
}
public class ClassD {
ArrayList<Effects> effects;
public ClassD() {
effects = new ArrayList<Effects>();
}
public void addEffect(Effects effect, int effectIntensity) {
//???
}
public void removeEffect(int index) {
effects.remove(index);
}
public ClassC applyEffects(ClassC classC) {
for (int i = 0; i < classC.getSize(); i++) {
ClassB classB = classC.getB(i);
//Apply all effects from effects ArrayList to classB
classC.setB(i, classB);
}
return classC;
}
}
public enum Effects {
//??? Code related to effect methods from ClassA
}
Where the question marks are that's where I don't know how to do this to achieve what I'm trying to do.

I'm going to shorten your example because you have a lot of things going on that I don't think really apply to the question you've asked.
enum constants are basically just public static final instances of the enum class. Therefore you are able to declare abstract methods and override them on each constant.
enum ClassAEffect {
A { #Override void apply(ClassA theA) { theA.effectA(); } },
B { #Override void apply(ClassA theA) { theA.effectB(); } },
C {
#Override
void apply(ClassA theA) {
theA.effectC();
}
};
abstract void apply(ClassA theA);
}
class ClassD {
List<ClassAEffect> effects = new ArrayList<>();
void add(ClassAEffect effect) { effects.add(effect); }
void apply(List<ClassA> list) {
for(ClassA theA : list)
for(ClassAEffect effect : effects)
effect.apply(theA);
}
}
ClassD theD = new ClassD();
theD.add(ClassAEffect.B);
theD.apply(Arrays.asList(new ClassA()));
enum may or may not be appropriate. For example if your design demanded effects for multiple classes, it may be much better to use regular interfaces.
interface Effect<T> {
void apply(T theT);
}
Effect<ClassA> classAEffectA = new Effect<>() {
#Override
public void apply(ClassA theA) {
theA.effectA();
}
};
As another answer notes, this is basically like command pattern and Wikipedia contains a Java example strikingly similar to your own.
Also, in Java 8, you may use method references directly.
class ClassD implements Consumer<List<ClassA>> {
List<Consumer<ClassA>> effects = new ArrayList<>();
void add(Consumer<ClassA> effect) { effects.add(effect); }
#Override
public void accept(List<ClassA> theList) {
for(ClassA theA : theList)
for(Consumer<ClassA> effect : effects)
effect.accept(theA);
}
}
ClassD theD = new ClassD();
// ClassA::effectB implicitly creates a Consumer<ClassA>
// that calls effectB on the ClassA that is passed to it
theD.add(ClassA::effectB);
theD.accept(Arrays.asList(new ClassA()));

Maybe you could use a variant of the command pattern for this?
Class D would be the Invoker and save all the effects (commands) that you want to execute in an array/list. If you don't want to add effects during runtime you could add them in the constructor.
ClassD would have a method executeAllOn(ClassC) that executes all the effects on the objects of ClassB in the ClassC array.
Reference: Command Pattern [wikipedia]
Edit after I saw your example, would look something like this:
public class ClassD {
ArrayList<Effect> effects;
HashMap<Effect, Integer> intensity;
public ClassD() {
effects = new ArrayList<Effects>();
}
public void addEffect(Effects effect, int effectIntensity) {
effects.add(effect)
intensity.put(effect, effectIntensity)
}
public void removeEffect(int index) {
effects.remove(index);
intensity.remove(effects.get(index))
}
public ClassC applyEffects(ClassC classC) {
for (int i = 0; i < classC.getSize(); i++) {
ClassB classB = classC.getB(i);
for (Effect effect : effects) {
effect.execute(classB, intensity.get(effect))
}
classC.setB(i, classB);
}
return classC;
}
}

Related

Passing lambda argument to constructor and using object in lambda

I have this scenario:
class ClassB{
ClassB(){
ClassA a = new ClassA(() -> a.foo());
}
}
class ClassA{
ClassA(Runnable onChange) {
}
public void foo(){
System.out.println("Hello");
}
}
And I get "Variable 'a' might not have been initialized". I understand why this is happening. Is there a work around or do I have to restructure my classes?
Without changing any of your types, this should work:
class ClassB {
ClassB() {
AtomicReference<A> ref = new AtomicReference<>(); // holder for instance
ClassA a = new ClassA(() -> ref.get().foo());
ref.set(a);
}
}
But you cannot invoke your lambda (Runnable#run) in your constructor, because a still has the value null. Only after the constructor has completed, the value is assigned.
Another possibility could be using a Consumer instead of a Runnable:
class ClassB {
ClassB() {
ClassA a = new ClassA(that -> that.foo()); // or maybe even: A::foo
}
}
class ClassA {
ClassA(Consumer<A> onChange) {
}
public void foo() {
System.out.println("Hello");
}
}
// call outside of `A`:
consumer.accept(a);
// or, inside of `A`:
consumer.accept(this);
Without seeing the rest of the code, it is difficult to give a good solution.
I think you should consider refactoring your code and use a different approach.
It's hard to tell without the full code but I suspect the design is not optimal.
With that said, here is something you could do which is similar to your approach.
Make ClassA Runnable and abstract:
abstract class ClassA implements Runnable{
private final Runnable onChange;
protected ClassA() {
this.onChange = this;
}
public void foo(){
System.out.println("Hello");
}
}
In ClassB you can implement an anonymous ClassA:
class ClassB {
ClassB() {
ClassA a = new ClassA() {
#Override
public void run() {
foo();
}
};
}
}

How to use 2 classes having same methods but without a parent class?

Let's assume we have 2 classes in Java 8, ClassA and ClassB. ClassA is a dependency class which cannot be changed in any way. ClassB is kind of like a copy of ClassA but with some modifications. ClassB cannot extend ClassA, but has almost the exact same functions as ClassA.
public class ClassB {
public ClassB(...) {}
public int update(...) {}
public String query(...) {}
.
.
.
}
So the above structure is similarly present in ClassA as well.
Say I want to code 2 other classes ClassC that uses an instance of ClassA and ClassD that uses an instance of ClassB. ClassC and ClassD have the exact same code except for the instances of ClassA and ClassB.
public class ClassC {
ClassA tmp;
public ClassC(...) {
tmp = new ClassA(...);
}
public void doSomething(...) {
tmp.update(...);
tmp.query(...);
}
.
.
.
}
public class ClassD {
ClassB tmp;
public ClassD(...) {
tmp = new ClassB(...);
}
public void doSomething(...) {
tmp.update(...);
tmp.query(...);
}
.
.
.
}
From the examples, it can be seen that ClassC and ClassD have the same functions but use a different Class for tmp
Is there any way that code duplication can be avoided? Can there be some way that I can write most of the functions of ClassC and ClassD as generic code and then have ClassC and ClassD extend this generic code?
Attempts at a solution
I tried a way that basically creates an interface class in a weird way. I define a ClassE that creates abstractions of ClassA and ClassB functions and also implements all the functions of ClassC and ClassD
public abstract class ClassE {
public ClassE(...) {}
public abstract int update(...);
public abstract String query(...);
public void doSomething(...) {
tmp.update(...);
tmp.query(...);
}
.
.
.
}
Then basically, ClassC and ClassD extend ClassE
public class ClassC extends ClassE {
ClassA tmp;
public ClassC(...) {
tmp = new ClassA(...);
}
public int update(...) {
return tmp.update(...);
}
public String query(...) {
return tmp.query()
}
.
.
.
}
public class ClassD extends ClassE {
ClassB tmp;
public ClassD(...) {
tmp = new ClassB(...);
}
public int update(...) {
return tmp.update(...);
}
public String query(...) {
return tmp.query()
}
.
.
.
}
Is this the best approach to the problem? Can there be a more suitable approach?
you could create an interface, not an abstract class. A generic interface. It would be as follows:
public interface class ClassE <G> {
int update(G attr);
String query(G attr);
void doSomething(G attr);
}
You must create the class implements:
public class ImplementClassA implements ClassE<ClassA> {
public int update(ClassA attr){
.
.
.
}
public String query(ClassA attr){
.
.
.
}
public void doSomething(ClassA attr){
.
.
.
}
}
public class ImplementClassB implements ClassE<ClassB> {
public int update(ClassB attr){
.
.
.
}
public String query(ClassB attr){
.
.
.
}
public void doSomething(ClassB attr){
.
.
.
}
}
In class c, interfaces could be used. In ClassC, you could use the interfaces, so you pass the instance of the type you need, be it the implementation of ClassA or ClassB
public class ClassC <G> {
private ClassE tmp;
public ClassC(ClassE tmp) {
this.tmp = tmp;
}
public int update(G attr) {
return tmp.update(attr);
}
public String query(G attr) {
return tmp.query(attr)
}
.
.
.
}
Ex,:
ClassC<ClassA> teste = new ClassC<ClassA>(new ImplementClassA());
ClassA save = new ClassA();
teste.update(save);
ClassC<ClassB> teste2 = new ClassC<ClassB>(new ImplementClassB());
ClassB save2 = new ClassB();
teste2.update(save2);
What comes to mind here is what domain driven design calls an anti corruption layer.
Meaning: you create an abstraction around the parts you want to separate yourself from, and your code only uses your own abstractions
In your case:
You create some interface that contains the functionality your classes C and D will want to use
you create two implementations of that interface, one using a class A object, the other one derives its functionality from a class B object
Now your classes C and D just need to be passed the corresponding impl classes. They rely on your interface only, so you are free to refactor them as you find useful.
And note: creating your own interface is the best solution here. Your classes A and B do not have any "type" relationship. Therefore generics aren't of any help here.
I think you are probably hoping for something that is called "duck typing". That is a concept from other languages, where you say "being a duck means: it can quack() and it can walk()" for example. That would mean: when two different classes share certain methods, you can have a "view" that defines a type that has these methods, and both these classes are of that "view type". But java doesn't support that (scala does, btw), and generics don't help with that.
You can create a delegate class for ClassA and ClassB:
public class delegateAB {
private ClassA a;
private ClassB b;
public delegateAB(ClassA a) {
this.a = a;
}
public delegateAB(ClassB b) {
this.b = b;
}
public int update(...) {
return a!=null?a.update(...):b.update(...)
}
// ... other common delegated methods.
}
And then you can instantinate this class either with ClassA or ClassB, so from that point you can use the delegate class in your code, like this:
public class ClassCD {
DelegateAB tmp;
public ClassCD(ClassA a, ...) {
tmp = new DelegateAB(a);
}
public ClassCD(ClassB b, ...) {
tmp = new DelegateAB(b);
}
public void doSomething(...) {
tmp.update(...);
tmp.query(...);
}
.
.
.
}
It's not an exceptionally nice solution but it does the trick.

Class A instantiates a Class B instance. How can the Instance of ClassB call a method of class A?

I have 2 classes, and I have made one class (Class A) instantiate a Class B object.
I have a method in Class B that I want to call a method in Class A.
I'm working on a larger project for practicing Java, so I am simplifying things here.
// Class A:
public class ClassA {
private int number;
private ClassB instanceOfB = new ClassB();
public ClassA {
number = 0;
}
public void incrementNumber {
number++;
}
public void incrementNumberLongWay {
instanceOfB.incrementNumberInA()
}
}
// Class B:
public class ClassB {
public void incrementNumberInA() {
// My desire: Call Class A's incrementNumber method
// What should I put here?
}
}
How do I make sure incrementNumberLongWay works? Class A has been instantiated, and it's method incrementNumberLongWay is called, so this should call ClassB's method incrementNumberInA
I know this seems extremely convoluted, but the reason I'm doing this, is because in my program I'm not incrementing numbers, but instead doing some logic in Class B, and only wanting to affect Class A in certain cases.
You can't do this with the code provided. Relationships are by default one way. B doesn't know about A so cannot access it.
What you can do is pass a reference of A to B in it's construction process and then access A via that reference.
One solution would be to pass a method of A as a callback.
For example:
public class ClassA {
private int number;
private ClassB instanceOfB = new ClassB();
public ClassA {
number = 0;
}
public void incrementNumber {
number++;
}
public void incrementNumberLongWay {
instanceOfB.incrementNumberInA(this::increment);
// alternatively
// instanceOfB.incrementNumberInA(() -> incrementNumber());
}
}
public class ClassB {
public void incrementNumberInA(Runnable callbackMethod) {
callbackMethod.run();
}
}
This removes B's dependency on A, and instead allows a general callback mechanism.
However, for such a simple scenario this approach isn't advised.
It's probably a bad idea in general to have a circular dependency in this way. One approach to break the cycle would be to have a third class (classC?) that implements the increment logic (or whatever your real-world equivalent is), and have classA and classB instances each reference classC. That way there's no case where two classes know about each other.
ClassB doesn't know anything about ClassA. So, you couldn't do it.
The ugly decision is
public void incrementNumberLongWay() {
instanceOfB.incrementNumberInA(this);
}
and in
public class ClassB {
public void incrementNumberInA(ClassA cl) {
cl.incrementNumber();
}
}
You can't call methods from class A from class B as class B has no reference to an object of class a. You could, however, pass class A's current number state to class B as parameter, and return a value from class B which class A can then get and use.
For example:
public class A {
private int number;
public A(int number) {
this.number = number;
}
public void incrementNumber(boolean largeIncrement) {
if(largeIncrement) {
B bInstance = new this.B();
number = bInstance.incrementNumberLongWay(number);
}
else {
number++;
}
}
private class B {
private B() {
// if some initialization is needed...
}
public int incrementNumberLongWay(int num) {
num += 1000;
return num;
}
}
}
Hope this is what you wanted.

How to find instance of class which is calling method

I know about way how to find which class is calling my method, but this is not sufficient to my.
I have a problem that I have about 200 instances of same class(base class) and they have unique identifier which I can use for analysing problem.
Is there some way, how to find which instances called some method?
I know that debugger allow it, can I do it some how from a code?
You'd pass a reference for that instance to the method being called. For example, say you have two objects:
class ObjectA {
public void methodA() {
new ObjectB().methodB();
}
}
class ObjectB {
public void methodB() {
// How can I know who called me?
}
}
If MethodB needs to know which instance of ObjectA called it, then it would accept that information as a parameter:
class ObjectA {
public void methodA() {
new ObjectB().methodB(this);
}
}
class ObjectB {
public void methodB(ObjectA caller) {
// "caller" is who called me
}
}
There are lots of ways to tweak this. For example, maybe any given instance of ObjectB should have a reference to the ObjectA which created it:
class ObjectA {
public void methodA() {
new ObjectB(this).methodB();
}
}
class ObjectB {
private final ObjectA caller;
public ObjectB(ObjectA caller) {
this.caller = caller;
}
public void methodB() {
// "caller" called me
}
}
Or perhaps you don't want to couple the two objects together and want a more generic approach. You claim that the objects have some kind of identifier, what is that identifier? A String perhaps?
class ObjectA {
private String identifier;
// other code
public void methodA() {
new ObjectB().methodB(identifier);
}
}
class ObjectB {
public void methodB(String callerID) {
// "callerID" identifies who called me
}
}

Why is super.super.method(); not allowed in Java?

I read this question and thought that would easily be solved (not that it isn't solvable without) if one could write:
#Override
public String toString() {
return super.super.toString();
}
I'm not sure if it is useful in many cases, but I wonder why it isn't and if something like this exists in other languages.
What do you guys think?
EDIT:
To clarify: yes I know, that's impossible in Java and I don't really miss it. This is nothing I expected to work and was surprised getting a compiler error. I just had the idea and like to discuss it.
It violates encapsulation. You shouldn't be able to bypass the parent class's behaviour. It makes sense to sometimes be able to bypass your own class's behaviour (particularly from within the same method) but not your parent's. For example, suppose we have a base "collection of items", a subclass representing "a collection of red items" and a subclass of that representing "a collection of big red items". It makes sense to have:
public class Items
{
public void add(Item item) { ... }
}
public class RedItems extends Items
{
#Override
public void add(Item item)
{
if (!item.isRed())
{
throw new NotRedItemException();
}
super.add(item);
}
}
public class BigRedItems extends RedItems
{
#Override
public void add(Item item)
{
if (!item.isBig())
{
throw new NotBigItemException();
}
super.add(item);
}
}
That's fine - RedItems can always be confident that the items it contains are all red. Now suppose we were able to call super.super.add():
public class NaughtyItems extends RedItems
{
#Override
public void add(Item item)
{
// I don't care if it's red or not. Take that, RedItems!
super.super.add(item);
}
}
Now we could add whatever we like, and the invariant in RedItems is broken.
Does that make sense?
I think Jon Skeet has the correct answer. I'd just like to add that you can access shadowed variables from superclasses of superclasses by casting this:
interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
int x = 3;
void test() {
System.out.println("x=\t\t" + x);
System.out.println("super.x=\t\t" + super.x);
System.out.println("((T2)this).x=\t" + ((T2)this).x);
System.out.println("((T1)this).x=\t" + ((T1)this).x);
System.out.println("((I)this).x=\t" + ((I)this).x);
}
}
class Test {
public static void main(String[] args) {
new T3().test();
}
}
which produces the output:
x= 3
super.x= 2
((T2)this).x= 2
((T1)this).x= 1
((I)this).x= 0
(example from the JLS)
However, this doesn't work for method calls because method calls are determined based on the runtime type of the object.
I think the following code allow to use super.super...super.method() in most case.
(even if it's uggly to do that)
In short
create temporary instance of ancestor type
copy values of fields from original object to temporary one
invoke target method on temporary object
copy modified values back to original object
Usage :
public class A {
public void doThat() { ... }
}
public class B extends A {
public void doThat() { /* don't call super.doThat() */ }
}
public class C extends B {
public void doThat() {
Magic.exec(A.class, this, "doThat");
}
}
public class Magic {
public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
String methodOfParentToExec) {
try {
Type type = oneSuperType.newInstance();
shareVars(oneSuperType, instance, type);
oneSuperType.getMethod(methodOfParentToExec).invoke(type);
shareVars(oneSuperType, type, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
Class<?> loop = clazz;
do {
for (Field f : loop.getDeclaredFields()) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(target, f.get(source));
}
loop = loop.getSuperclass();
} while (loop != Object.class);
}
}
I don't have enough reputation to comment so I will add this to the other answers.
Jon Skeet answers excellently, with a beautiful example. Matt B has a point: not all superclasses have supers. Your code would break if you called a super of a super that had no super.
Object oriented programming (which Java is) is all about objects, not functions. If you want task oriented programming, choose C++ or something else. If your object doesn't fit in it's super class, then you need to add it to the "grandparent class", create a new class, or find another super it does fit into.
Personally, I have found this limitation to be one of Java's greatest strengths. Code is somewhat rigid compared to other languages I've used, but I always know what to expect. This helps with the "simple and familiar" goal of Java. In my mind, calling super.super is not simple or familiar. Perhaps the developers felt the same?
There's some good reasons to do this. You might have a subclass which has a method which is implemented incorrectly, but the parent method is implemented correctly. Because it belongs to a third party library, you might be unable/unwilling to change the source. In this case, you want to create a subclass but override one method to call the super.super method.
As shown by some other posters, it is possible to do this through reflection, but it should be possible to do something like
(SuperSuperClass this).theMethod();
I'm dealing with this problem right now - the quick fix is to copy and paste the superclass method into the subsubclass method :)
In addition to the very good points that others have made, I think there's another reason: what if the superclass does not have a superclass?
Since every class naturally extends (at least) Object, super.whatever() will always refer to a method in the superclass. But what if your class only extends Object - what would super.super refer to then? How should that behavior be handled - a compiler error, a NullPointer, etc?
I think the primary reason why this is not allowed is that it violates encapsulation, but this might be a small reason too.
I think if you overwrite a method and want to all the super-class version of it (like, say for equals), then you virtually always want to call the direct superclass version first, which one will call its superclass version in turn if it wants.
I think it only makes rarely sense (if at all. i can't think of a case where it does) to call some arbitrary superclass' version of a method. I don't know if that is possible at all in Java. It can be done in C++:
this->ReallyTheBase::foo();
At a guess, because it's not used that often. The only reason I could see using it is if your direct parent has overridden some functionality and you're trying to restore it back to the original.
Which seems to me to be against OO principles, since the class's direct parent should be more closely related to your class than the grandparent is.
Calling of super.super.method() make sense when you can't change code of base class. This often happens when you are extending an existing library.
Ask yourself first, why are you extending that class? If answer is "because I can't change it" then you can create exact package and class in your application, and rewrite naughty method or create delegate:
package com.company.application;
public class OneYouWantExtend extends OneThatContainsDesiredMethod {
// one way is to rewrite method() to call super.method() only or
// to doStuff() and then call super.method()
public void method() {
if (isDoStuff()) {
// do stuff
}
super.method();
}
protected abstract boolean isDoStuff();
// second way is to define methodDelegate() that will call hidden super.method()
public void methodDelegate() {
super.method();
}
...
}
public class OneThatContainsDesiredMethod {
public void method() {...}
...
}
For instance, you can create org.springframework.test.context.junit4.SpringJUnit4ClassRunner class in your application so this class should be loaded before the real one from jar. Then rewrite methods or constructors.
Attention: This is absolute hack, and it is highly NOT recommended to use but it's WORKING! Using of this approach is dangerous because of possible issues with class loaders. Also this may cause issues each time you will update library that contains overwritten class.
#Jon Skeet Nice explanation.
IMO if some one wants to call super.super method then one must be want to ignore the behavior of immediate parent, but want to access the grand parent behavior.
This can be achieved through instance Of. As below code
public class A {
protected void printClass() {
System.out.println("In A Class");
}
}
public class B extends A {
#Override
protected void printClass() {
if (!(this instanceof C)) {
System.out.println("In B Class");
}
super.printClass();
}
}
public class C extends B {
#Override
protected void printClass() {
System.out.println("In C Class");
super.printClass();
}
}
Here is driver class,
public class Driver {
public static void main(String[] args) {
C c = new C();
c.printClass();
}
}
Output of this will be
In C Class
In A Class
Class B printClass behavior will be ignored in this case.
I am not sure about is this a ideal or good practice to achieve super.super, but still it is working.
Look at this Github project, especially the objectHandle variable. This project shows how to actually and accurately call the grandparent method on a grandchild.
Just in case the link gets broken, here is the code:
import lombok.val;
import org.junit.Assert;
import org.junit.Test;
import java.lang.invoke.*;
/*
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
Please don't actually do this... :P
*/
public class ImplLookupTest {
private MethodHandles.Lookup getImplLookup() throws NoSuchFieldException, IllegalAccessException {
val field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
return (MethodHandles.Lookup) field.get(null);
}
#Test
public void test() throws Throwable {
val lookup = getImplLookup();
val baseHandle = lookup.findSpecial(Base.class, "toString",
MethodType.methodType(String.class),
Sub.class);
val objectHandle = lookup.findSpecial(Object.class, "toString",
MethodType.methodType(String.class),
// Must use Base.class here for this reference to call Object's toString
Base.class);
val sub = new Sub();
Assert.assertEquals("Sub", sub.toString());
Assert.assertEquals("Base", baseHandle.invoke(sub));
Assert.assertEquals(toString(sub), objectHandle.invoke(sub));
}
private static String toString(Object o) {
return o.getClass().getName() + "#" + Integer.toHexString(o.hashCode());
}
public class Sub extends Base {
#Override
public String toString() {
return "Sub";
}
}
public class Base {
#Override
public String toString() {
return "Base";
}
}
}
Happy Coding!!!!
I would put the super.super method body in another method, if possible
class SuperSuperClass {
public String toString() {
return DescribeMe();
}
protected String DescribeMe() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return "I am super";
}
}
class ChildClass extends SuperClass {
public String toString() {
return DescribeMe();
}
}
Or if you cannot change the super-super class, you can try this:
class SuperSuperClass {
public String toString() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return DescribeMe(super.toString());
}
protected String DescribeMe(string fromSuper) {
return "I am super";
}
}
class ChildClass extends SuperClass {
protected String DescribeMe(string fromSuper) {
return fromSuper;
}
}
In both cases, the
new ChildClass().toString();
results to "I am super super"
It would seem to be possible to at least get the class of the superclass's superclass, though not necessarily the instance of it, using reflection; if this might be useful, please consider the Javadoc at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
public class A {
#Override
public String toString() {
return "A";
}
}
public class B extends A {
#Override
public String toString() {
return "B";
}
}
public class C extends B {
#Override
public String toString() {
return "C";
}
}
public class D extends C {
#Override
public String toString() {
String result = "";
try {
result = this.getClass().getSuperclass().getSuperclass().getSuperclass().newInstance().toString();
} catch (InstantiationException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
}
public class Main {
public static void main(String... args) {
D d = new D();
System.out.println(d);
}
}
run:
A
BUILD SUCCESSFUL (total time: 0 seconds)
I have had situations like these when the architecture is to build common functionality in a common CustomBaseClass which implements on behalf of several derived classes.
However, we need to circumvent common logic for specific method for a specific derived class. In such cases, we must use a super.super.methodX implementation.
We achieve this by introducing a boolean member in the CustomBaseClass, which can be used to selectively defer custom implementation and yield to default framework implementation where desirable.
...
FrameworkBaseClass (....) extends...
{
methodA(...){...}
methodB(...){...}
...
methodX(...)
...
methodN(...){...}
}
/* CustomBaseClass overrides default framework functionality for benefit of several derived classes.*/
CustomBaseClass(...) extends FrameworkBaseClass
{
private boolean skipMethodX=false;
/* implement accessors isSkipMethodX() and setSkipMethodX(boolean)*/
methodA(...){...}
methodB(...){...}
...
methodN(...){...}
methodX(...){
if (isSkipMethodX()) {
setSKipMethodX(false);
super.methodX(...);
return;
}
... //common method logic
}
}
DerivedClass1(...) extends CustomBaseClass
DerivedClass2(...) extends CustomBaseClass
...
DerivedClassN(...) extends CustomBaseClass...
DerivedClassX(...) extends CustomBaseClass...
{
methodX(...){
super.setSKipMethodX(true);
super.methodX(...);
}
}
However, with good architecture principles followed in framework as well as app, we could avoid such situations easily, by using hasA approach, instead of isA approach. But at all times it is not very practical to expect well designed architecture in place, and hence the need to get away from solid design principles and introduce hacks like this.
Just my 2 cents...
IMO, it's a clean way to achieve super.super.sayYourName() behavior in Java.
public class GrandMa {
public void sayYourName(){
System.out.println("Grandma Fedora");
}
}
public class Mama extends GrandMa {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName();
}else {
System.out.println("Mama Stephanida");
}
}
}
public class Daughter extends Mama {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName(lie);
}else {
System.out.println("Little girl Masha");
}
}
}
public class TestDaughter {
public static void main(String[] args){
Daughter d = new Daughter();
System.out.print("Request to lie: d.sayYourName(true) returns ");
d.sayYourName(true);
System.out.print("Request not to lie: d.sayYourName(false) returns ");
d.sayYourName(false);
}
}
Output:
Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha
I think this is a problem that breaks the inheritance agreement.
By extending a class you obey / agree its behavior, features
Whilst when calling super.super.method(), you want to break your own obedience agreement.
You just cannot cherry pick from the super class.
However, there may happen situations when you feel the need to call super.super.method() - usually a bad design sign, in your code or in the code you inherit !
If the super and super super classes cannot be refactored (some legacy code), then opt for composition over inheritance.
Encapsulation breaking is when you #Override some methods by breaking the encapsulated code.
The methods designed not to be overridden are marked
final.
In C# you can call a method of any ancestor like this:
public class A
internal virtual void foo()
...
public class B : A
public new void foo()
...
public class C : B
public new void foo() {
(this as A).foo();
}
Also you can do this in Delphi:
type
A=class
procedure foo;
...
B=class(A)
procedure foo; override;
...
C=class(B)
procedure foo; override;
...
A(objC).foo();
But in Java you can do such focus only by some gear. One possible way is:
class A {
int y=10;
void foo(Class X) throws Exception {
if(X!=A.class)
throw new Exception("Incorrect parameter of "+this.getClass().getName()+".foo("+X.getName()+")");
y++;
System.out.printf("A.foo(%s): y=%d\n",X.getName(),y);
}
void foo() throws Exception {
System.out.printf("A.foo()\n");
this.foo(this.getClass());
}
}
class B extends A {
int y=20;
#Override
void foo(Class X) throws Exception {
if(X==B.class) {
y++;
System.out.printf("B.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("B.foo(%s) calls B.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
}
class C extends B {
int y=30;
#Override
void foo(Class X) throws Exception {
if(X==C.class) {
y++;
System.out.printf("C.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("C.foo(%s) calls C.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
void DoIt() {
try {
System.out.printf("DoIt: foo():\n");
foo();
Show();
System.out.printf("DoIt: foo(B):\n");
foo(B.class);
Show();
System.out.printf("DoIt: foo(A):\n");
foo(A.class);
Show();
} catch(Exception e) {
//...
}
}
void Show() {
System.out.printf("Show: A.y=%d, B.y=%d, C.y=%d\n\n", ((A)this).y, ((B)this).y, ((C)this).y);
}
}
objC.DoIt() result output:
DoIt: foo():
A.foo()
C.foo(C): y=31
Show: A.y=10, B.y=20, C.y=31
DoIt: foo(B):
C.foo(B) calls C.super.foo(B)
B.foo(B): y=21
Show: A.y=10, B.y=21, C.y=31
DoIt: foo(A):
C.foo(A) calls C.super.foo(A)
B.foo(A) calls B.super.foo(A)
A.foo(A): y=11
Show: A.y=11, B.y=21, C.y=31
It is simply easy to do. For instance:
C subclass of B and B subclass of A. Both of three have method methodName() for example.
public abstract class A {
public void methodName() {
System.out.println("Class A");
}
}
public class B extends A {
public void methodName() {
super.methodName();
System.out.println("Class B");
}
// Will call the super methodName
public void hackSuper() {
super.methodName();
}
}
public class C extends B {
public static void main(String[] args) {
A a = new C();
a.methodName();
}
#Override
public void methodName() {
/*super.methodName();*/
hackSuper();
System.out.println("Class C");
}
}
Run class C Output will be:
Class A
Class C
Instead of output:
Class A
Class B
Class C
If you think you are going to be needing the superclass, you could reference it in a variable for that class. For example:
public class Foo
{
public int getNumber()
{
return 0;
}
}
public class SuperFoo extends Foo
{
public static Foo superClass = new Foo();
public int getNumber()
{
return 1;
}
}
public class UltraFoo extends Foo
{
public static void main(String[] args)
{
System.out.println(new UltraFoo.getNumber());
System.out.println(new SuperFoo().getNumber());
System.out.println(new SuperFoo().superClass.getNumber());
}
public int getNumber()
{
return 2;
}
}
Should print out:
2
1
0
public class SubSubClass extends SubClass {
#Override
public void print() {
super.superPrint();
}
public static void main(String[] args) {
new SubSubClass().print();
}
}
class SuperClass {
public void print() {
System.out.println("Printed in the GrandDad");
}
}
class SubClass extends SuperClass {
public void superPrint() {
super.print();
}
}
Output: Printed in the GrandDad
The keyword super is just a way to invoke the method in the superclass.
In the Java tutorial:https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super.
Don't believe that it's a reference of the super object!!! No, it's just a keyword to invoke methods in the superclass.
Here is an example:
class Animal {
public void doSth() {
System.out.println(this); // It's a Cat! Not an animal!
System.out.println("Animal do sth.");
}
}
class Cat extends Animal {
public void doSth() {
System.out.println(this);
System.out.println("Cat do sth.");
super.doSth();
}
}
When you call cat.doSth(), the method doSth() in class Animal will print this and it is a cat.

Categories

Resources