Java constructor chaining and avoid code repetition - java

I have immutable class and want add new constructor without duplicating code in both constructors.
I have class:
public class Test {
private final String stringParameter;
public Test() {
stringParameter = "firstReallyLongDefaultString";
}
public Test(String s) {
stringParameter = s;
}
}
And I want to add the new constructor with "char" parameter, something like this:
public Test(char s) {
if(Character.isLetter(s)) {
stringParameter = "firstReallyLong" + s + "DefaultString";
} else {
stringParameter = "firstReallyLongDefaultString";
}
}
How can I do it without the code repetition of the long string? I would like to call "this()" constructor in else branch but it's not possible.

public Test(char s) {
this(Character.isLetter(s) ? "firstReallyLong" + s + "DefaultString" : "firstReallyLongDefaultString");
}

You also could chain them more explicitly, removing some code repetition:
public class Test {
private static final String DEFAULT_VALUE = "firstReallyLongDefaultString";
private final String stringParameter;
public Test() {
this(DEFAULT_VALUE);
}
public Test(String s) {
stringParameter = s;
}
public Test(char c) {
this(prepareString(c));
}
private static String prepareString(char c) {
if(Character.isLetter(s)) {
return "firstReallyLong" + s + "DefaultString";
} else {
return DEFAULT_VALUE;
}
}
}
The "firstReallyLongDefaultString" better to be done as a private constant to avoid repetition.

Like this:
public Test(char s) {
super();
if(Character.isLetter(s)) {
stringParameter = "firstReallyLong" + s + "DefaultString";
}
}

A factory method gives you more flexibility:
public static Test create(char c) {
final String parameter;
if(Character.isLetter(s)) {
parameter = "firstReallyLong" + s + "DefaultString";
} else {
parameter = "firstReallyLongDefaultString";
}
return new Test(parameter);
}
This can't be inherited in subclasses, however if you want your class to be strictly immutable it should be final.

Related

Java ASM method override check

I have a problem with method override checks. I can detect simple override relations, but if the parent class has generics and the abstract method uses type parameters (return value/args), my code breaks down because the method description is not equal to the checked method.
Example:
public interface ISetting<T> {
public T method();
}
public class Setting implements ISetting<Integer> {
public Integer method() {
//Something
}
}
In ISetting, the method description is ()Ljava/lang/Object;
and in Setting, the method description is ()Ljava/lang/Integer;
How I can check this Override ?
On my head no thoughts come, how I can make this >~< All ideas which come to my head are bad (example: ignore check on desc, but overload method just break this idea)
Note that your issue does not only apply to generic supertype. You can also override a method with a more specific return type, with no Generics involved, e.g.
interface SomeInterface {
Object method();
}
class SomeImplementation implements SomeInterface {
#Override
public Integer method() {
return null;
}
}
You have to understand the concept of bridge methods.
A bridge method performs the task of overriding a method on the byte code level, having exactly the same parameter types and return type as the overridden method, and delegates to the actual implementation method.
Since the bridge method only consists of this invocation instruction, some type casts if required, and the return instruction, it is easy to parse such a method to find the actual method it belongs to, without dealing with the complex rules of the Generic type system.
Using, the following helper classes
record MethodSignature(String name, String desc) {}
record MethodInfo(int access, String owner, String name, String desc) {
MethodSignature signature() {
return new MethodSignature(name, desc);
}
}
final class MethodAndBridges {
MethodInfo actual;
final List<MethodInfo> bridges = new ArrayList<>();
MethodAndBridges(MethodSignature sig) {}
void set(MethodInfo mi) {
if(actual != null) throw new IllegalStateException();
actual = mi;
}
void addBridge(MethodInfo mi) {
bridges.add(mi);
}
}
We can gather the information in a form ready for checking override relations with the ASM library as follows:
class MethodCollector extends ClassVisitor {
static Map<MethodSignature, MethodAndBridges> getMethods(ClassReader cr) {
MethodCollector mc = new MethodCollector();
cr.accept(mc, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return mc.found;
}
final Map<MethodSignature, MethodAndBridges> found = new HashMap<>();
String owner, superClass;
List<String> interfaces;
protected MethodCollector() {
super(Opcodes.ASM9);
}
#Override
public void visit(int version, int acc,
String name, String sig, String superName, String[] ifNames) {
owner = name;
superClass = superName;
this.interfaces = ifNames == null? List.of(): List.of(ifNames);
}
#Override
public MethodVisitor visitMethod(
int acc, String name, String desc, String sig, String[] exceptions) {
MethodInfo mi = new MethodInfo(acc, owner, name, desc);
if((acc & Opcodes.ACC_BRIDGE) == 0) {
found.computeIfAbsent(mi.signature(), MethodAndBridges::new).set(mi);
return null;
}
return new MethodVisitor(Opcodes.ASM9) {
#Override public void visitMethodInsn(
int op, String owner, String name, String tDesc, boolean i) {
found.computeIfAbsent(new MethodSignature(name, tDesc),
MethodAndBridges::new).addBridge(mi);
}
};
}
}
To demonstrate how this work, let’s enhance your example, to address more cases
interface SupplierOfSerializable {
Serializable get();
}
interface ISetting<T extends CharSequence> extends Supplier<T>, Consumer<T> {
T get();
#Override void accept(T t);
Number method(int i);
static void method(Object o) {}
private void method(Number n) {}
}
class Setting implements ISetting<String>, SupplierOfSerializable {
public String get() {
return "";
}
#Override
public void accept(String t) {}
public Integer method(int i) {
return i;
}
static void method(Object o) {}
void method(Number n) {}
}
and check the override relations (only considering the direct interfaces, without recursion)
public class CheckOverride {
public static void main(String[] args) throws IOException {
MethodCollector mc = new MethodCollector();
new ClassReader(Setting.class.getName())
.accept(mc, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
Map<MethodSignature, MethodAndBridges> implMethods = mc.found;
Map<MethodInfo, Set<MethodInfo>> overrides = new HashMap<>();
for(String ifType: mc.interfaces) {
Map<MethodSignature, MethodAndBridges> ifMethods
= MethodCollector.getMethods(new ClassReader(ifType));
System.out.println("interface " + ifType.replace('/', '.'));
printMethods(ifMethods);
System.out.println();
ifMethods.values().removeIf(CheckOverride::nonOverridable);
implMethods.forEach((sig, method) -> {
if(nonOverridable(method)) {
overrides.putIfAbsent(method.actual, Set.of());
return;
}
var overridden = ifMethods.get(sig);
if(overridden == null && method.bridges.isEmpty()) {
overrides.putIfAbsent(method.actual, Set.of());
return;
}
Set<MethodInfo> set = overrides.compute(method.actual,
(k, s) -> s == null || s.isEmpty()? new HashSet<>(): s);
if(overridden != null) set.add(overridden.actual);
for(var mi: method.bridges) {
overridden = ifMethods.get(mi.signature());
if(overridden != null) set.add(overridden.actual);
}
});
}
System.out.println("class " + mc.owner.replace('/', '.'));
printMethods(implMethods);
System.out.println();
System.out.println("Final result");
System.out.println("class " + mc.owner.replace('/', '.'));
overrides.forEach((m,overridden) -> {
System.out.println(" " + toDeclaration(m, false));
if(!overridden.isEmpty()) {
System.out.println(" overrides");
overridden.forEach(o ->
System.out.println(" " + toDeclaration(o, true)));
}
});
}
static boolean nonOverridable(MethodAndBridges m) {
return (m.actual.access() & (Opcodes.ACC_PRIVATE|Opcodes.ACC_STATIC)) != 0
|| m.actual.name().startsWith("<");
}
static void printMethods(Map<MethodSignature, MethodAndBridges> methods) {
methods.forEach((sig, methodAndBridges) -> {
System.out.println(" "+toDeclaration(methodAndBridges.actual,false));
if(!methodAndBridges.bridges.isEmpty()) {
System.out.println(" bridges");
for(MethodInfo mi: methodAndBridges.bridges) {
System.out.println(" " + toDeclaration(mi, false));
}
};
});
}
private static String toDeclaration(MethodInfo mi, boolean withType) {
StringBuilder sb = new StringBuilder();
sb.append(Modifier.toString(mi.access() & Modifier.methodModifiers()));
if(sb.length() > 0) sb.append(' ');
String clName = mi.owner();
var mt = MethodTypeDesc.ofDescriptor(mi.desc());
if(mi.name().equals("<init>"))
sb.append(clName, clName.lastIndexOf('/') + 1, clName.length());
else {
sb.append(mt.returnType().displayName()).append(' ');
if(withType) sb.append(clName.replace('/', '.')).append('.');
sb.append(mi.name());
}
if(mt.parameterCount() == 0) sb.append("()");
else {
String sep = "(";
for(ClassDesc cd: mt.parameterList()) {
sb.append(sep).append(cd.displayName());
sep = ", ";
}
sb.append(')');
}
return sb.toString();
}
}
interface ISetting
public static void method(Object)
public abstract void accept(CharSequence)
bridges
public void accept(Object)
public abstract Number method(int)
private void method(Number)
public abstract CharSequence get()
bridges
public Object get()
interface SupplierOfSerializable
public abstract Serializable get()
class Setting
Setting()
public Integer method(int)
bridges
public Number method(int)
public void accept(String)
bridges
public void accept(Object)
public void accept(CharSequence)
static void method(Object)
public String get()
bridges
public Object get()
public CharSequence get()
public Serializable get()
void method(Number)
Final result
class Setting
public String get()
overrides
public abstract Serializable SupplierOfSerializable.get()
public abstract CharSequence ISetting.get()
Setting()
public Integer method(int)
overrides
public abstract Number ISetting.method(int)
public void accept(String)
overrides
public abstract void ISetting.accept(CharSequence)
void method(Number)
static void method(Object)
The code uses newer Java features, like var, record, and the constant API, but I think, the result is straight-forward enough for converting it to older Java versions, if really required.

Multiple Java 8 Enums with same methods

I have a series of enums which look like this except that the name and values are different:
/* Bone Diagnosis. Value is internal code stored in database. */
public enum BoneDiagnosis {
NORMAL(121),
ELEVATED(207),
OSTEOPENIA(314),
OSTEOPOROSIS(315);
private int value;
BoneDiagnosis(final int value) {
this.value = value;
}
/** Get localized text for the enumeration. */
public String getText() {
return MainProgram.localize(this.getClass().getSimpleName().toUpperCase() + ".VALUE." + this.name());
}
/** Convert enumeration to predetermined database value. */
public int toDB() {
return value;
}
/** Convert a value read from the database back into an enumeration. */
public static BoneDiagnosis fromDB(final Integer v) {
if (v != null) {
for (final BoneDiagnosis pc : values()) {
if (v == pc.toDB()) {
return pc;
}
}
}
return null;
}
}
I know I cannot extend enums, but is there some way to abstract this design to remove all the duplicate code in toDB(), fromDB(), and getText() that each class has? I looked at other questions like Is it possible to extend enum in Java 8? which had an example using an interface, but I could not figure out how to handle the constructor and the static method. I also cannot figure out how to remove the explicit reference to type BoneDiagnosis in the fromDB() method.
My dream would be to have each class merely be defined something like what follows, with all the other support wrapped up in whatever BoneDiagnosisComplexTypeDefinition is. Is this possible?
public enum BoneDiagnosisComplexTypeDefinition {
NORMAL(121),
ELEVATED(207);
OSTEOPENIA(314),
OSTEOPOROSIS(315)
}
You can minimize the per-enum code and the per-operation overhead using
#Target(ElementType.FIELD) #Retention(RetentionPolicy.RUNTIME)
public #interface DbId {
int value();
}
final class Helper extends ClassValue<Map<Object,Object>> {
static final Helper INSTANCE = new Helper();
#Override protected Map<Object, Object> computeValue(Class<?> type) {
Map<Object,Object> m = new HashMap<>();
for(Field f: type.getDeclaredFields()) {
if(f.isEnumConstant()) try {
Object constant = f.get(null);
Integer id = f.getAnnotation(DbId.class).value();
m.put(id, constant);
m.put(constant, id);
}
catch(IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
return Collections.unmodifiableMap(m);
}
}
public interface Common {
String name();
Class<? extends Enum<?>> getDeclaringClass();
default int toDB() {
return (Integer)Helper.INSTANCE.get(getDeclaringClass()).get(this);
}
default String getText() {
return MainProgram.localize(
getDeclaringClass().getSimpleName().toUpperCase() + ".VALUE." + name());
}
static <T extends Enum<T>&Common> T fromDB(Class<T> type, int id) {
return type.cast(Helper.INSTANCE.get(type).get(id));
}
}
public enum BoneDiagnosis implements Common {
#DbId(121) NORMAL,
#DbId(207) ELEVATED,
#DbId(314) OSTEOPENIA,
#DbId(315) OSTEOPOROSIS;
}
Test example
int id = BoneDiagnosis.OSTEOPENIA.toDB();
System.out.println("id = " + id);
BoneDiagnosis d = Common.fromDB(BoneDiagnosis.class, id);
System.out.println("text = " + d.getText());
Note that the reflective operations are only performed once per class using ClassValue which is especially designed for caching per-class meta data efficiently, thread safe and without preventing class unloading in environments where it matters. The actual toDB and fromDB are reduced to a hash lookups.
By the way, it’s important that this code uses getDeclaringClass() rather than getClass() as enums may have specializations like in enum Foo { BAR { … } … } where getClass() returns the specialization class rather than the enum type.
The interface approach is the only way to go. Here is another way to leverage interfaces to minimize code duplication in your enums.
Update:
Some have complained about reflection and casting. Here are two options without need for casting and one that does not require reflection.
Option1 (clean no reflection but requires extra method in enums):
public static interface BoneDiagnosisType{
public String name();
public int getValue();
default int toDB() {
return getValue();
}
default String getText(){
return MainProgram.localize( this.getClass().getSimpleName().toUpperCase() + ".VALUE." + name() );
}
public static < E extends Enum<E> & BoneDiagnosisType > E fromDB(Class<E> eClass, Integer v) {
if (v != null) {
for ( final E pc : eClass.getEnumConstants() ) {
if ( v == pc.toDB() ) {
return pc;
}
}
}
return null;
}
}
public static enum BoneDiagnosis1 implements BoneDiagnosisType{
NORMAL(121),
ELEVATED(207),
OSTEOPENIA(314),
OSTEOPOROSIS(315);
int value;
BoneDiagnosis1(int value) {
this.value = value;
}
public int getValue(){
return value;
}
}
public static enum BoneDiagnosis2 implements BoneDiagnosisType{
NORMAL(1121),
ELEVATED(1207),
OSTEOPENIA(1314),
OSTEOPOROSIS(1315);
int value;
BoneDiagnosis2(int value) {
this.value = value;
}
public int getValue(){
return value;
}
}
Option2 (requires reflection keeps enums as simple as possible):
public static interface BoneDiagnosisType{
public String name();
default int toDB() {
try{
Class<?> clazz = getClass();
Field field = clazz.getDeclaredField("value");
return field.getInt(this);
}catch(RuntimeException e){
throw e;
}catch(Exception e){
throw new RuntimeException(e);
}
}
default String getText(){
return MainProgram.localize( this.getClass().getSimpleName().toUpperCase() + ".VALUE." + name() );
}
public static < E extends Enum<E> & BoneDiagnosisType > E fromDB(Class<E> eClass, Integer v) {
if (v != null) {
for ( final E pc : eClass.getEnumConstants() ) {
if ( v == pc.toDB() ) {
return pc;
}
}
}
return null;
}
}
public static enum BoneDiagnosis1 implements BoneDiagnosisType{
NORMAL(121),
ELEVATED(207),
OSTEOPENIA(314),
OSTEOPOROSIS(315);
int value;
BoneDiagnosis1(int value) {
this.value = value;
}
}
public static enum BoneDiagnosis2 implements BoneDiagnosisType{
NORMAL(1121),
ELEVATED(1207),
OSTEOPENIA(1314),
OSTEOPOROSIS(1315);
int value;
BoneDiagnosis2(int value) {
this.value = value;
}
}
And the sample printout:
System.out.println( BoneDiagnosis1.NORMAL.toDB() + " : " + BoneDiagnosis1.NORMAL.getText() + " : " +
BoneDiagnosisType.fromDB( BoneDiagnosis1.class, 121 ) );
System.out.println( BoneDiagnosis1.ELEVATED.toDB() + " : " + BoneDiagnosis1.ELEVATED.getText() + " : " +
BoneDiagnosisType.fromDB( BoneDiagnosis1.class, 207 ) );
System.out.println( BoneDiagnosis2.NORMAL.toDB() + " : " + BoneDiagnosis2.NORMAL.getText() + " : " +
BoneDiagnosisType.fromDB( BoneDiagnosis2.class, 1121 ) );
System.out.println( BoneDiagnosis2.ELEVATED.toDB() + " : " + BoneDiagnosis2.ELEVATED.getText() + " : " +
BoneDiagnosisType.fromDB( BoneDiagnosis2.class, 1207 ) );
will give:
121 : BONEDIAGNOSIS1.VALUE.NORMAL : NORMAL
207 : BONEDIAGNOSIS1.VALUE.ELEVATED : ELEVATED
1121 : BONEDIAGNOSIS2.VALUE.NORMAL : NORMAL
1207: BONEDIAGNOSIS2.VALUE.ELEVATED : ELEVATED
Here's another way you could go about it using what some call the "virtual field pattern." It reduces the amount of repeated code per enum to one getter and one field. It also avoids reflection.
First create an interface for all the methods your enums have in common. In this example we'll call it Common.
public interface Common {
int getId();
String getName();
}
Create another interface that extends Common. This will have only one abstract method, which just returns an instance of Common. Give the other methods a default implementation that delegates to the Common instance.
public interface VirtualCommon extends Common {
Common getCommon();
#Override
default int getId() {
return getCommon().getId();
}
#Override
default String getName() {
return getCommon().getName();
}
}
Now create a concrete implementation of Common.
public class CommonImpl implements Common {
private int id;
private String name;
public CommonImpl(int id, String name) {
this.id = id;
this.name = name;
}
#Override
public int getId() {
return this.id;
}
#Override
public String getName() {
return this.name;
}
}
Or, if you want to save a few lines of code, instead of CommonImpl you can put a static method on Common that returns an anonymous class.
static Common of(final int id, final String name) {
return new Common() {
#Override
public int getId() {
return id;
}
#Override
public String getName() {
return name;
}
};
}
Now you can create each of your enums and they'll only need one field and one getter. Any class or enum that implements VirtualCommon will be a Common because it has a Common.
public enum EnumImpl implements VirtualCommon {
ALPHA(1, "Alpha"),
BETA(2, "Beta"),
DELTA(3, "Delta"),
GAMMA(4, "Gamma");
private final Common common;
EnumImpl(int id, String name) {
this.common = new CommonImpl(id, name);
}
#Override
public Common getCommon() {
return this.common;
}
}
This solution still has some boilerplate bridging code.
Use an Interface to define the calling interface and implement the common code in some class.
Here is a simple example:
File: BoneDiagnosis.java
public enum BoneDiagnosis
implements
CommonStuffs
{
NORMAL(121),
ELEVATED(207),
OSTEOPENIA(314),
OSTEOPOROSIS(315);
private CommonStuffsImpl commonStuffsImpl;
private int value;
BoneDiagnosis(final int theValue)
{
value = theValue;
commonStuffsImpl = new CommonStuffsImpl();
}
#Override
public int toDB()
{
return commonStuffsImpl.toDBImplementation(value);
}
}
File: CommonStuffs.java
public interface CommonStuffs
{
int toDB();
}
File: CommonStuffsImpl.java
public class CommonStuffsImpl
{
public int toDBImplementation(
final int value)
{
return value;
}
}

assert p.name("String").equals("Child String")

interface Parent {
public String name(Object b);
}
class Child implements Parent {
public String name(Object b) {
return [???];
}
public String name(String b) {
return "Child " + [???];
}
}
public class Exercise {
public static void main(String[] args) {
Parent p = new Child();
assert p.name("String").equals("Child String");
}
}
Is there any way to replace the '[???]' within the code above so that the assert returns trues?
I don't understand why the method name is overloaded. But you could use instanceof to check for the type of the parameter b.
public String name(Object b) {
if (b instanceof String) {
return name((String) b);
}
return "something else";
}
public String name(String b) {
return "Child " + b;
}

What would you like to correct and/or improve in this java implementation of Chain Of Responsibility?

package design.pattern.behavioral;
import design.pattern.behavioral.ChainOfResponsibility.*;
public class ChainOfResponsibility {
public static class Chain {
private Request[] requests = null;
private Handler[] handlers = null;
public Chain(Handler[] handlers, Request[] requests){
this.handlers = handlers;
this.requests = requests;
}
public void start() {
for(Request r : requests)
for (Handler h : handlers)
if(h.handle(r)) break;
}
}
public static class Request {
private int value;
public Request setValue(int value){
this.value = value;
return this;
}
public int getValue() {
return value;
}
}
public static class Handler<T> {
private Command<T> command = null;
public Handler(Command<T> command) {
this.command = command;
}
public boolean handle(T request) {
return command.execute(request);
}
}
public static abstract class Command<T>{
public abstract Boolean execute(T request);
}
}
class TestChainOfResponsibility {
public static void main(String[] args) {
new TestChainOfResponsibility().test();
}
private void test() {
new Chain(new Handler[]{ // chain of responsibility
new Handler<Request>(
new Command<Request>(){ // command
public Boolean execute(Request condition) {
boolean result = condition.getValue() >= 600;
if (result) System.out.println("You are rich: " + condition.getValue() + " (id: " + condition.hashCode() + ")");
return result;
}
}
),
new Handler<Request>(
new Command<Request>(){
public Boolean execute(Request condition) {
boolean result = condition.getValue() >= 100;
if(result) System.out.println("You are poor: " + condition.getValue() + " (id: " + condition.hashCode() + ")");
return result;
}
}
),
},
new Request[]{
new Request().setValue(600), // chaining method
new Request().setValue(100),
}
).start();
}
}
I don't think there is a meaningful answer to such a general question. Design patterns don't exist in isolation and don't have a "perfect form": they live in a context.
A pattern is a solution to a problem in a context.
So without knowing the context of your solution, there is not much we can say about it. What is the concrete problem you are trying to resolve with it? What forces are in play? What are your constraints? Do you have any problems / issues with the current solution? If you give more details about these, maybe we can give a better answer.
Lambda isn't very descriptive (to most developers). Is it something you are pulling in from functional language theory?
I'd probably just get rid of the 'controlling' class, and wire the individual handlers up to each other directly - use more of an IoC approach, basically.
Example (in C#, forgive me) per request...
public interface IIntMessage
{
void HandleMesasge(int i);
}
public class EvenPrinter : IIntMessage
{
private IIntMessage m_next;
public EvenPrinter(IIntMessage next)
{
m_next = next;
}
public void HandleMesasge(int i)
{
if(i % 2 == 0)
{
System.Console.WriteLine("Even!");
}
else
{
m_next.HandleMesasge(i);
}
}
}
public class OddPrinter : IIntMessage
{
private IIntMessage m_next;
public OddPrinter(IIntMessage next)
{
m_next = next;
}
public void HandleMesasge(int i)
{
if(i%2 == 1)
{
System.Console.WriteLine("Odd!");
}
else
{
m_next.HandleMesasge(i);
}
}
}
Note that we get rid of the "controlling" class altogether, and simply allow the request handlers to directly chain to each other, without having to go through an intermediary.
Also, I could probably extract out a 'base' chain-of-command request handler, removing some of the duplicate code.

Delegating method calls using variable number of arguments

This question came up in the course of my work programming; it's become irrelevant to the current task, but I'm still curious if anyone has an answer.
In Java 1.5 and up you can have a method signature using a variable number of arguments, with an ellipsis syntax:
public void run(Foo... foos) {
if (foos != null) {
for (Foo foo: foos) { //converted from array notation using autoboxing
foo.bar();
}
}
}
Suppose I want to do some operation on each foo in the foos list, and then delegate this call to some field on my object, preserving the same API. How can I do it? What I want is this:
public void run(Foo... foos) {
MyFoo[] myFoos = null;
if (foos != null) {
myFoos = new MyFoo[foos.length];
for (int i = 0; i < foos.length; i++) {
myFoos[i] = wrap(foos[i]);
}
}
run(myFoos);
}
public void run(MyFoo... myFoos) {
if (myFoos!= null) {
for (MyFoo myFoo: myFoos) { //converted from array notation using autoboxing
myFoo.bar();
}
}
}
This doesn't compile. How can I accomplish this (passing a variable number of MyFoo's to the run(MyFoo...) method)?
Is this what you want?
public class VarArgsTest {
public static class Foo {}
public static class MyFoo extends Foo {
public MyFoo(Foo foo) {}
}
public static void func(Foo... foos) {
MyFoo [] myfoos = new MyFoo[foos.length];
int i=0;
for (Foo foo : foos) {
myfoos[i++] = new MyFoo(foo);
}
func(myfoos);
}
public static void func(MyFoo... myfoos) {
for (MyFoo m : myfoos) {
System.out.println(m);
}
}
public static void main(String [] args) throws Exception {
func(new Foo(), new Foo(), new Foo());
}
}
I tried it and did NOT get a compile error. What is the actual error you are seeing? Here is the code I used. Perhaps i did something different:
public class MultipleArgs {
public static void main(String [] args){
run(new Foo("foo1"), new Foo("foo2"), new Foo("foo3"));
}
public static void run(Foo... foos){
MyFoo[] myFoos = null;
if (foos != null) {
myFoos = new MyFoo[foos.length];
for (int i = 0; i < foos.length; i++) {
myFoos[i] = wrap(foos[i]);
}
}
run(myFoos);
}
public static void run(MyFoo... myFoos){
if (myFoos!= null) {
for (MyFoo myFoo: myFoos) {
myFoo.bar();
}
}
}
private static class Foo {
public final String s;
public Foo(String s){
this.s = s;
}
#Override
public String toString(){
return s;
}
}
private static class MyFoo{
private final String s;
public MyFoo(String s){
this.s = s;
}
public void bar(){
System.out.println(s);
}
#Override
public String toString(){
return s;
}
}
private static MyFoo wrap(Foo foo){
return new MyFoo(foo.s);
}
}
This doesn't answer your question; it's incidental, but you don't need the null test. Here's proof:
public class VarargsTest extends TestCase {
public void testVarargs() throws Exception {
assertEquals(0, fn());
}
private int fn(String...strings) {
return strings.length;
}
}
If the method is called without any arguments, the varargs list is an empty array, not null.
I think the actual solution to your question would be to rename the second function.
use java reflections.

Categories