This question already has answers here:
How to refer to the outer class in another instance of a non-static inner class?
(3 answers)
Closed 8 years ago.
I am currently wondering if there is a good way of implementing an equals method for a non-static inner class in Java. I basically a class Foo with an inner-class Bar like this:
public class Foo {
private final String foo; // constructor omitted
public /* non-static */ class Bar {
private final String bar; // constructor omitted
#Override
public boolean equals(Object other) {
return other != null && other.getClass() == getClass()
&& ((Bar) other).bar.equals(this.bar)
&& Foo.this.equals(Foo.((Bar) other)); // Will, of course, not compile.
}
}
#Override
public boolean equals(Object other) {
return other != null && other.getClass() == getClass()
&& ((Foo) other).foo.equals(foo);
}
}
My classes are a lot more complex in reality and I want to reuse the Foo#equals method from within Bar#equals in order to save me a lot of code. I am now considering to make the "inner-class-relationship" explicit in order to being able to refer to the "outer" class. However, then I have to add accessor methods manually and I want to avoid this. I cannot get rid of the feeling that there should be a Java approach of doing this.
Yes, this is possible. This is often done when you need to pass around "Key" objects that represent a unique identifier for some set of data but do not either have the data or want to transport it.
class SomeData {
private String data;
public static class Key {
private final int firstId;
private final int secondId;
public Key(int firstId, int secondId) {
this.firstId = firstId;
this.secondId = secondId;
}
public boolean equals(Object x) {
if(!(x instanceof Key))
return false;
Key key = ((Key)x);
return this.firstId == key.firstId
&& this.secondId == key.secondId;
}
// implement hashCode as well
}
}
In the example above the inner class is static but that doesn't really matter. The only reason I set it that way is so that exterior classes could construct it. Make sure when you are overriding the .equals that you also get the .hashCode. They should change with each other.
Related
I was wondering, what if I have the following case:
public class MyObject<T> {
private T myTObject;
public void setMyTObject(T m) {
myTObject = m;
}
public T getMyTObject() {
return myTObject;
}
}
And now I want that class to react something like these:
MyObject<ObjectA> objA = new MyObject<ObjectA>();
ObjectA objAInstance = objA.getObjectA();
or
objA.setObjectA(otherObjectAInstance);
Is there a way to dynamically create methods based on T class name?
Or should I better extend ObjectA to MyObject and create those methods using super.get/seMyObject()?
For clarification:
The idea is to have a getter and setter method generated dynamically
so, if I create an instance of:
MyObject<A> objA = new MyObject<A>();
I would be able to call method:
objA.getA();
getA() will call internally getMyTObject() or just return myTObject
so MyObject may react based on T class and generate the corresponding method.
I have updated member attribute to differentiate from MyObject class, it may lead to confusion. also fixed Method return and parameter Type.
Update Answer is completely changed.
Sounds like you want to use something through reflection. The problem with truly dynamically generating the method names is that, as others have commented, it would have to be done in bytecode which means that other classes trying to use your dynamic classes don't have Java code to refer to. It can be done, but it would be a mess.
Instead, here's a possible solution using generics. Please note that this is something of a quick and dirty hack; I leave it to you to refine it. You define an interface with the getters and setters you want, with whatever you want them named:
package com.example.dcsohl;
public interface IntegerWrapper {
public Integer getInteger();
public void setInteger(Integer i);
}
And then, to use them, you use this class to do the heavy lifting. Note that the error checking isn't very good; for example, it doesn't check that "getFoo" at all corresponds to the name of the class being passed in; nor does it validate that the "foo" in "getFoo" matches the "setFoo" method. This is something you can improve on.
package com.example.dcsohl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyWrapper<T> implements InvocationHandler {
Class<T> clazz = null;
T myvalue = null;
public static <W,T> W getInstance(Class<W> clazz, Class<T> clazz2) {
ProxyWrapper<T> wrapper = new ProxyWrapper<T>();
wrapper.setClass(clazz2);
#SuppressWarnings("unchecked")
W proxy = (W)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, wrapper);
return proxy;
}
private void setClass(Class<T> clazz) {
this.clazz = clazz;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// getter has no arguments
if (method.getName().startsWith("get") && (args == null || args.length == 0)) {
return myvalue;
} else if (method.getName().startsWith("set") && args.length == 1) {
Object o = args[0];
if (o.getClass().isAssignableFrom(clazz)) {
#SuppressWarnings("unchecked")
T val = (T)o;
myvalue = val;
return null;
}
} else {
throw new Exception();
}
return null;
}
}
Finally, to use it, here's a quick sample:
package com.example.dcsohl;
public class Main {
public static void main(String[] args) {
Integer foo = 5;
IntegerWrapper wrapper = ProxyWrapper.getInstance(IntegerWrapper.class, Integer.class);
wrapper.setInteger(foo);
Integer bar = wrapper.getInteger();
System.out.println(bar);
}
}
It seems like a lot of work just to avoid writing simple wrapper classes, and you'd be right, but reflection has its uses, and this is something of a sampler.
I have a class like this:
import java.util.List;
import java.util.String;
import javax.xml.bind.annotation.XmlType;
#XmlType
public class Foo {
private List<Foo> compound;
private String bar;
// private method used internally to know
// if this is a compound instance
private boolean isCompound() {
return compound != null && compound.size() != 0;
}
// public setter for compound instance var
public void setCompound(List<Foo> compound) {
this.compound = compound;
}
// public getter for compound instance var
public List<Foo> getCompound() {
return compound;
}
public void setBar(String bar) {
this.bar = bar;
}
public String getBar() {
return bar;
}
}
In normal use, this class behaves as you would expect. The methods getCompound and setCompound get and set the compound list. However, I'm using this class as an object that's passed in a web service built using JAX-WS. When the JAX-WS compiler sees this class, it ignores the setCompound and getCompound accessors, and the only property that appears in the XSD is bar.
After banging my head against the wall for most of the day, I decided to try changing the name of the private method isCompound to isACompound and suddenly everything worked as you'd expect. JAX-WS created the correct schema for the compound property.
What seems to be happening is that JAX-WS is seeing the isCompound method (even though it's private) and treating it as a getter with no corresponding setter and therefore ignoring the real public accessors for compound.
Is there anything in the Java Bean specification that says you can't have a private is<Something> method where <something> is also the name of a non-boolean property, which also has its own accessors? Surely anything using reflection on the class should simply ignore private methods?
What happens if you change:
return compound != null && compound.size() != 0;
//To:
private boolean isCompound() {
boolean check = false;
if(compound !=null && compound.size()!=0){
check = true;
}else{
check =false;
}
return check;
}
//or
#XmlAccessorType(XmlAccessType.NONE) on the class and #XmlElement and #XmlAttribute on the get/set methods.
Consider the following enum class
public enum ClassA {
CHECK1("X", 0),
CHECK2("Y", 2),
CHECK3("Z", 1);
private final String id;
private final String cdValue;
private ClsA(String id, String cdValue) {
this.id = id;
this.cdValue = cdValue;
}
private String getId() {
return id;
}
private String getCdValue() {
return cdValue ;
}
private static final List<String> cdValues = new ArrayList<String>();
static {
for (ClassA clsA : ClassA.values()) {
cdValues.add(clsA.getCdValue());
}
}
public boolean isCdValue(String cdValue)
{
if clsValues.contains(cdValue)
return true;
else return false;
}
}
The question that I have is does the method isCdValue has to be static. I have to use this method isCdValue for every input given by the client. Therefore the method parameter cdValue changes for every input.
If it cannot be static then I would like to know how I can access this method. Please note I am primarily interested in learning about static of non-static method call. If it is a non-static call in a enum then how can we call this non static method. I am not trying to resolve the issue of how to get about checking the cdValue exists or not. It is just an example.
does the method isCdValue has to be static.
Yes, the method isCdValue has to be static here.
An enum is a special kind of class. An enum constant defines an instance of the enum type. An enum type has no instances other than those defined by its enum constants. Hence new can not be used to instantiate an enum.
An enum type has no instances other than those defined by its enum
constants. It is a compile-time error to attempt to explicitly
instantiate an enum type (§15.9.1).
Refer this
If you have to put the checking method in the Enum, I think it should be static
you can do this check:
ClassA.isCdValue(para)
Note that, you cannot new an Enum object. So if the method in your Enum, and it is not static, you cannot call it unless you have an Instance. but the goal of your method is checking if the string could be an instance.
another possibility is, use an immutable collection in your Enumm, and make it static and public. Then you could just call ClassA.CD_VALUES.contains(para)
If you want to access it from ClsA, you will have to make it static, if you want to access it from an instance of ClsSa then it doesn't.
A couple of other things: where do you declare clsValues in the first place?
There's no need for the complex if, you may replace this:
public boolean isCdValue(String cdValue)
{
if clsValues.contains(cdValue)
return true;
else return false;
}
with this
public boolean isCdValue(String cdValue){
return clsValues.contains(cdValue)
}
Last little thing, I'd strongly suggest you put curly braces around all your if and else's clauses, I've spent many a debugging hour because someone added a second line under the else, fooled by the indent and thinking it would only execute on the else.
You can use something like this, you do not need static List but the method has to be static as answered by Kent,
public static ClassA getClassAByCDValue(String cdValue)
{
for(ClassA value: ClassA.values())
{
if(value.cdValue.contains(cdValue))
{
return value;
}
}
return null;
}
public static boolean isCDValue(String cdValue)
{
for(ClassA value: ClassA.values())
{
if(value.cdValue.contains(cdValue))
{
return true;
}
}
return false;
}
Using above will be more appropriate as you just have to take care with adding/removing items in enum.
public enum Batman
{
Rat, Cat, Bat;
private boolean isMatch;
// Constructor
Batman()
{
this.isMatch = (this.compareTo(Bat) == 0) ? true : false;
}
public boolean isMatch()
{
return this.isMatch;
}
}
For the constructor line I get the error:
Cannot refer to the static enum field Batman.Bat within an initializer
I am primarily trying to figure out if the specific ENUM can be identified in the constructor.
Also the reason I am thinking of saving the "isMatch" value, is that I don't want to evaluate what it should be every time.
I know form the very beginning, so I just want to save the value, and thus when a call is made it is not an evaluation
but simply passing the value back
I know there are other ways to solve this:
Modify the constructor to accept parameter:
Rat(false), Cat(false), Bat(true);
// Constructor
Batman(boolean isMatch)
{
this.isMatch = isMatch;
}
Change isMatch()
public boolean isMatch()
{
return (this.compareTo(Bat) == 0) ? true : false;
}
Any advice would be great.
Thanks
As others have said, you can not reference a specific Enum value in the constructor. The obvious solution would be to write this:
public enum Batman
{
Rat, Cat, Bat;
public boolean isMatch()
{
return this == Bat;
}
}
(BTW, you don't need equals with Enum)
But if the evaluation this == Bat really bothers you, you can override isMatch for Bat:
public enum Batman
{
Rat, Cat,
Bat {
#Override
public boolean isMatch() {
return true;
}
};
public boolean isMatch()
{
return false;
}
}
This way, you have no comparison, instead you use methods overrided by enum values.
And a variation on this, just for the fun:
public enum Batman
{
Rat, Cat,
Bat {{
this.isMatch = true;
}};
protected boolean isMatch = false;
public boolean isMatch()
{
return isMatch;
}
}
(note the notation{{ }} and the fact that isMatch must be protected instead of private so the Bat instance can access it.)
From Book Effective Java:
Enum constructors aren’t permitted to access the enum’s static fields,
except for compile-time constant fields. This restriction is necessary
because these static fields have not yet been initialized when the
constructors run.
You definitely can't reference any specific ENUM in the constructor, since it needs to be created when you want to refernece it and you are just creating it!
I would go with option 1, as you make the particular knowledge you rely on external to the internal implementation of the enum itself.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Implement a final class without the “final” keyword
I want to create an immutable class in Java without using the final keyword.
I think smt like should work fine
class Immutable {
private int i;
public static Immutable create(int i){
return new Immutable(i);
}
private Immutable(int i){this.i = i;}
public int getI(){return i;}
}
But final is preferable.
The final keyword won't make your class inmutable. It will avoid your class to be extended from another class.
public final class Foo {
//....
}
public class Bar extends Foo {
//COMPILATION ERROR!
}
An adecuated class design is what will make you class inmutable, as you can see at duffymo answer.
Note that you can declare as final the fields that you will initialize at the constructor:
class Foo {
private final int state
public Foo(int v) {
this.state=v;
}
//....
}
The difference is that, while at duffymo example, the value ccould be changed from inner routines (i.e, a method adds one to the value, kind of a counter), at my example you wouldn't be able to do so.
Let's try to avoid absolutely the use of the final keyword:
public class Foo {
private int state;
private Foo(int v) {
this.state=v;
}
public static Foo getInstance(int value) {
return new Foo(value);
}
}
You only can get an instance of Foo accesing the Foo.getInstance method.
But anyway, you can extend the Foo class and make it mutable
I was wrong here. I won't compile, as you can acceess the Foo constructor.
public class Bar extends Foo {
private int ohNopes;
//COMPILATION ERROR!
public Bar(int v) {
this.ohNopes=v;
}
}
So, it seems it can be done, after all.
The problem with an immutable class not being final is that, subclasses may not be immutable.
Here is an example from the Java API, java.lang.String is immutable and final, if a string is passed to one of your methods you can be sure that it will remain in a consistent state.
the following will not compile because String is final:
public class MyString extends java.Lang.String {
public MyString(String original) {
Super(original);
}
#Override
public String toString() {
return String.valueOf(System.currentTimeMillis());
}
On the other hand, java.ma.BigDecimal itself is immutable, but it is not final and allowed to be subclassed. This opens up a range of issues. If a BigDecimal is passes to one of your methods you can't rely on the fact that no one has overridden BigDecimal like you can with String. subclasses of BigDecimal could potentially replace its methods with others which give unpredictable results.
The following will compile because BigDecimal is not immutable:
public class MyBigDecimal extends java.math.BigDecimal {
public MyBigDecimal(double val) {
super(val);
}
private int count = 0;
// override intValue which changes the state of this instance
#Override
public int intValue() {
return count++;
}
// rinse and repeat for the rest of the BigDecimal methods...
}
You cannot rely on he state of BigDecimal instances passed into your code, you should make Defensive copies of non final classes if you need to rely on their immutability.
I can't imagine why you object to using final, but here's a class that will get the job done. I know there are subtleties regarding serialization and reflection, but this can't be changed without special shenanigans:
public class Immutable
{
private int value;
public Immutable(int v)
{
this.value = v;
}
public int getValue() { return this.value; }
}
The class should set all its values in the constructor, and provide no setters (methods that modify class members).
You can create a class then create a .jar and use the jar as resource.