I have error when I send this:
myClaass.put(new ImenResult(1).Show());
myClaass.put(new ImenResult(2));
I understand why I have got this problem because I send to class which have interface parameter. My question is: what I have to add to interface to send this data and haven`t got error because this structure have to be this same (not my decision) because later I can send String or another things (Class). I know this is very difficult question.
Program:
Class_1 myClaass = new Class_1();
myClaass.put(new ImenResult(1).Show());
myClaass.put(new ImenResult(2));
myClaass.put(new ImenResult(3));
ImenResult:
public class ImenResult implements IImenResult{
public Integer i;
public ImenResult(Integer i ) {
this.i = i;
}
#Override
public Integer Show() {
return i;
}
Class_1
public class Class_1 implements IQRack{
public List<IAdant> adan;
public void put(IAdant value) {
adan.add(value);
}
}
IAdan
public interface IAdant {
}
Thanks for help I told you this is difficult question (of course for people who are not Java specialist) but topic is fixed. I gave you points. Thanks again for helped. [closed]
you should implement the method put(Integer) in Class_1 for this to work
public class Class_1 implements IQRack {
public List<IAdant> adan;
public void put(IAdant value) {
adan.add(value);
}
void put(Integer Show) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
UPDATE
After your comment i think this is what you are trying to do:
public class Class_1 implements IQRack {
private List<IAdant> adan = new ArrayList<IAdant>();
public Class_1(IAdant i) {
this.put(i);
}
void put(IAdant Show) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
public class IAdant {
Boolean bValue;
String sValue;
Integer iValue;
public IAdant(Object o) {
if (o.getClass().isInstance(new Integer(1))) {
iValue = (Integer) o;
} else if (o.getClass().isInstance(false)) {
bValue = (Boolean) o;
} else if (o.getClass().isInstance("")) {
sValue = (String) o;
}
}
}
The line: myClaass.put(new ImenResult(1).Show()); will fail, because myClaass.put() is expecting to get an object that implements IAdant, but you are sending and Integer. Integer does not implement IAdant.
myClaass.put(new ImenResult(1).Show());
myClaass.put(new ImenResult(2));
first case would file, cuz, your put method expects IAdant(any that that implements IAdant) and you are passing an integer as the show method would return one.
second case would fail because of the same reason that your ImenResult class is not implementing or a Type of IAdant.
if you want the second case to work, implement IAdant in ImenResult class.
public class ImenResult implements IImenResult,IAdant{
//implement the methods from both the interfaces
}
now myClaass.put(new ImenResult(2)); line would work with out any compiler errors.
If you wanna get the first case myClaass.put(new ImenResult(1).Show()); to compile , you have to overload the put method in myClass class.
public void put(int val) {
//do your logic here
}
Related
is there any ClassDef like IntDef in annotation to restrict the type of annotation as my example below?
#ClassDef({
Integer, String, Long
})
public #interface MyRestrictedData {
}
As a result, I can use it as: public void showData(#MyRestrictedData Object myData)
This reqirement CAN'T be resolve by annotation processor.
It can only do by runtime container, like Spring.
But in fact, the container is just help you check it by proxy. Why can't you do it by yourself? Like this:
public class MyRestrictedData {
public static void check(Object o){
if(!(String.class.isInstance(o) || Integer.class.isInstance(o) || Long.class.isInstance(o)))
throw new IllegalArgumentException("Must be String, Integer or Long.");
}
}
public void showData(Object myData) {
MyRestrictedData.check(myData);
// then do your work
}
EDIT
If you really want check in compile period, the only way is what zhh said, override your method. I don't know what logic need handle String, Integer and Long together. But if you really need, you can do:
public void showData(String s){
showData((Object)s);
}
public void showData(Integer i){
showData((Object)i);
}
public void showData(Long l){
showData((Object)l).
}
private void showData(Object o){
// do your work here, note this method is PRIVATE
}
In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
Given the following abstract class:
public abstract class BaseVersionResponse<T extends BaseVO> {
public abstract void populate(T versionVO);
}
and the following child class:
public class VersionResponseV1 extends BaseVersionResponse<VersionVOV1>
{
protected String testFieldOne;
protected String testFieldTwo;
public String getTestFieldOne() {
return testFieldOne;
}
public void setTestFieldOne(String value) {
this.testFieldOne = value;
}
public String getTestFieldTwo() {
return testFieldTwo;
}
public void setTestFieldTwo(String value) {
this.testFieldTwo = value;
}
#Override
public void populate(VersionVOV1 versionVO) {
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
I desire to do something like this from a calling method:
public void getVersionInfo(String version) {
BaseVO versionVO = null;
BaseVersionResponse<? extends BaseVO> baseVersionResponse = null;
baseVersionResponse = createVersionResponse(version);
versionVO = createVersionVO(version);
baseVersionResponse.populate(versionVO);
}
where createVersionResponse(...) and createVersionVO(...) look like this:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) {
BaseVersionResponse<? extends BaseVO> specificVersionResponse = null;
if (version.equalsIgnoreCase("V1")) {
specificVersionResponse = new VersionResponseV1();
} else if (version.equalsIgnoreCase("V2"))
specificVersionResponse = new VersionResponseV2();
return specificVersionResponse;
}
public BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
and VersionVOV1 looks like this:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
private String fieldTwo = null;
private String fieldThree = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public String getFieldTwo() {
return fieldTwo;
}
public void setFieldTwo(String fieldTwo) {
this.fieldTwo = fieldTwo;
}
public String getFieldThree() {
return fieldThree;
}
public void setFieldThree(String fieldThree) {
this.fieldThree = fieldThree;
}
}
My problem arises when I try to compile this line of code:
baseVersionResponse.populate(versionVO);
in getVersionInfo(...). I'm getting a message that looks like this:
The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO)
on the populate method above.
My thought was (which is apparently incorrect) that since the baseVersionResponse is, at this point in the code, actually a specific child instance, that the class would know exactly which populate method to call from that specific child class.
What am I doing wrong here? Is there a better way to do this if this isn't the correct approach?
Thank you for your time!
Ok, I took a better look at this today. The problem is that the wildcard, while the right way to go, precludes you from doing:
BaseVO versionVO = createVersionVO(version);
Because the populate call wants an extension of BaseVO, not an actual BaseVO, which doesn't qualify. That means you can't pass that versionVO variable directly.
So, to keep the type checking in place, which I think is good because you'll always want an implementation, leave pretty much everything as-is above, and change your BaseVersionResponse class to something like:
public abstract class BaseVersionResponse<T extends BaseVO> {
public T getVersion(BaseVO versionVO) {
try {
return (T) versionVO;
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
}
public abstract void populate(BaseVO versionVO);
}
So, populate method now takes a BaseVO, and there's a new getVersion method to do some explicit casting for us. This should be ok since we know that the factory will always supply the right thing, but if another caller doesn't, an IllegalArgumentException is thrown.
Now, in your response class implementation, change the populate method accordingly:
public void populate(BaseVO version) {
VersionVOV1 versionVO = getVersion(version);
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
So, we've changed the populate method to take BaseVO, and the getVersion method does the casting for us. All the other type checks still apply, and we're good to go.
The casting makes it feel not as clean, but for the factory approach you're using, it's really the only way (I can think of) to keep the guarantees made by the type declarations and the code pattern in tact.
Hope that helps!
If you just take out the capture of type (the "<?>"), and leave it unchecked, it should work just fine. Even using type Object would have compiled.
But, given your specific example, what you probably want is the method:
public BaseVersionResponse<?> createVersionResponse(String version)
Changed to:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version)
Then, instead of using
BaseVersionResponse<?>
use
BaseVersionResponse<? extends BaseVO>
Since you know that the return type will be one of those things that implements the interface/class.
How i can check if a class is of a determinated type for example:
// PacketHandler.java
public interface PacketHandler<T> {
public void handlePacket(T packet);
}
// PacketReader.java
public void read() {
Packet packet = // Read some input
for(PacketHandler packetHandler : packetHandlers) {
if (packetHandler is the type of packet) { // here is the problem
packetHandler.handlePacket(packet);
}
}
}
public void registerHandler(PacketHandler<?> packetHandler) {
packetHandlers.add(packetHandler);
}
// Main
packetReader.registerHandler(new PacketHandler<RandomPacket>() {
public void handlePacket(RandomPacket packet) {
// I handle the packet
}
});
I know that this question maybe seems stupid;
but how to solve this problem?
**Edit*****
Jon Skeet, so the class should be:
public class RandomClass implements PacketHandler {
public boolean handlePacket(Packet packet) {
if (packet instanceof PacketThatThisClassHandle) {
//handle with casting
return true;
} else {
return false;
}
}
}
Unfortunately Java generics use type erasure, meaning that at execution time, any particular PacketHandler<T> is just PacketHandler as far as the VM is concerned.
You may want to change your code to:
public interface PacketHandler {
// The parameter type can be Object if you really want
boolean tryHandlePacket(Packet packet);
}
... and make a PacketHandler just return false if it doesn't know how to handle a particular packet type.
Then you can just use:
for (PacketHandler handler : handlers) {
if (handler.tryHandlePacket(packet)) {
break;
}
}
(That's assuming you only want a single handler to actually handle any packet type.)
If you still want a generic interface, you'd either need a boolean handlesPacket(Packet) method, or possibly a Class<T> getPacketType() method. Either way it's still going to be a pain in terms of casting the packet to the right type...
If you have lots of packet handlers, you could potentially create an abstract base class:
public abstract class AbstractPacketHandler<T extends Packet>
implements PacketHandler {
private final Class<T> packetType;
protected AbstractPacketHandler(Class<T> packetType) {
this.packetType = packetType;
}
protected abstract void handlePacket(T packet);
public boolean tryHandlePacket(Packet packet) {
if (!packetType.isInstance(packet)) {
return false;
}
handlePacket(packetType.cast(packet));
return true;
}
}
Then you can write:
public class FooPacketHandler extends PacketHandler<Foo> {
public FooPacketHandler() {
super(Foo.class);
}
protected void handlePacket(Foo packet) {
...
}
}
Type erasure won't make this attempt easy. The mapping part it's quite easy, you can use a HashMap. But the problem is that the handlePacket method accepts a parameter of type T, which forces you to cast the object to that type before passing it to the handler.
To avoid relaxing the constraint you could use a two level invokation, something like:
interface Packet { }
class ConcretePacket implements Packet { }
HashMap<Class<?>, PacketHandler<?>> mapping =
new HashMap<Class<?>, PacketHandler<?>>();
public abstract class PacketHandler<T extends Packet> {
PacketHandler(Class<T> clazz) {
mapping.put(clazz, this);
}
public final void handlePacket(Packet packet) {
doHandlePacket((T)packet);
}
public abstract void doHandlePacket(T packet);
}
public class ConcretePacketHandler extends PacketHandler<ConcretePacket>
{
ConcretePacketHandler()
{
super(ConcretePacket.class);
}
public void doHandlePacket(ConcretePacket s) {
// whatever
}
}
public void receivedPacket(Packet packet) {
PacketHandler<?> handler = mapping.get(packet.getClass());
if (handler != null)
handler.handlePacket(packet);
}
Mind that this could not work in certain situations (maybe with different classloaders involved) and that, to manage subclasses of PacketManager, you will need to find a better way to retrieve the correct handler, eg by using a List<Pair<Class<?>,PacketHandler<?>>> so that you can check
if (listElement.clazz.isAssignableFrom(packet.getClass()))
handler = listElement.handler;
maybe even using priorities so that the exact class is found before a possible superclass.
I don't exactly understand what you are trying to get but you could possibly use:
if ( type.isInstance(obj) ) {
//do something
}
http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#isInstance%28java.lang.Object%29
[EDIT: I've rewritten the code to further simplify it and focus on the issue at hand]
I'm working on this particular piece of code:
class SimpleFactory {
public SimpleFactory build() {return null}
}
class SimpleFactoryBuilder {
public Object build(final Class builderClazz) {
return new SimpleFactory() {
#Override
public SimpleFactory build() {
return new builderClazz.newInstance();
}
};
}
}
However, the builder in the return statement triggers the error "Cannot find symbol newInstance". It's as if builderClazz wasn't recognized as a class object.
How can I make it work?
EDIT: SOLUTION (thanks to dcharms!)
The code above is a partial simplification of the code I was dealing with. The code below is still simplified but includes all the components involved and includes the solution provided by dcharms.
package com.example.tests;
interface IProduct {};
interface ISimpleFactory {
public IProduct makeProduct();
}
class ProductImpl implements IProduct {
}
class SimpleFactoryBuilder {
public ISimpleFactory buildFactory(final Class productMakerClazz) {
return new ISimpleFactory() {
#Override
public IProduct makeProduct() {
try {
// the following line works: thanks dcharms!
return (IProduct) productMakerClazz.getConstructors()[0].newInstance();
// the following line -does not- work.
// return new productMakerClazz.newInstance();
}
catch (Exception e) {
// simplified error handling: getConstructors() and newInstance() can throw 5 types of exceptions!
return null;
}
}
};
}
}
public class Main {
public static void main(String[] args) {
SimpleFactoryBuilder sfb = new SimpleFactoryBuilder();
ISimpleFactory sf = sfb.buildFactory(ProductImpl.class);
IProduct product = sf.makeProduct();
}
}
You cannot instantiate a new object this way. builder is a Class object. Try instead the following:
return builder.getConstructors()[0].newInstance(anInput);
Note: this assumes you are using the first constructor. You may be able to use getConstructor() but I'm not sure how it would behave with the generic type.