Old question but no answer provides a concrete solution in Java to solve the issue in a clean way.
 
In fact, not easy but very interesting question. Here is my contribution.
Ok the method to be called is decided at compile time. Is there a
  workaround to avoid using the instanceof operator?
As said in the excellent @DaveFar answer, Java supports only the single-dispatch method.
In this dispatching mode, the compiler bounds the method to invoke as soon as the compilation by relying on the declared types of the parameters and not their runtime types.
I have a collection (or list or array list) in which I want to put
  both String values and double values.
To solve the answer in a clean way and use a double dispatch, we have to bring abstraction for the manipulated data.
Why ?
Here a naive visitor approach to illustrate the issue :
public class DisplayVisitor {
    void visit(Object o) {
        System.out.println("object"));
    }
    void visit(Integer i) {
        System.out.println("integer");
    }
    void visit(String s) {
        System.out.println("string"));
    }
}
Now, question : how visited classes may invoke the visit() method ?
The second dispatch of the double dispatch implementation relies on the "this" context of the class that accepts to be visited.
So we need to have a accept() method in Integer, String and Object classes to perform this second dispatch :
public void accept(DisplayVisitor visitor){
    visitor.visit(this);
}
But impossible ! Visited classes are built-in classes : String, Integer, Object.
So we have no way to add this method.
And anyway, we don't want to add that.
So to implement the double dispatch, we have to be able to modify the classes that we want to pass as parameter in the second dispatch.
So instead of manipulating Object and List<Object> as declared type, we will manipulate Foo and List<Foo> where the Foo class is a wrapper holding the user value.
Here is the Foo interface :
public interface Foo {
    void accept(DisplayVisitor v);
    Object getValue();
}
getValue() returns the user value.
It specifies Object as return type but Java supports covariance returns (since the 1.5 version), so we could define a more specific type for each subclass to avoid downcasts.
ObjectFoo
public class ObjectFoo implements Foo {
    private Object value;
    public ObjectFoo(Object value) {
        this.value = value;
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
    @Override
    public Object getValue() {
        return value;
    }
}
StringFoo 
public class StringFoo implements Foo {
    private String value;
    public StringFoo(String string) {
        this.value = string;
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
    @Override
    public String getValue() {
        return value;
    }
}
IntegerFoo 
public class IntegerFoo implements Foo {
    private Integer value;
    public IntegerFoo(Integer integer) {
        this.value = integer;
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
    @Override
    public Integer getValue() {
        return value;
    }
}
Here is the DisplayVisitor class visiting Foo subclasses :
public class DisplayVisitor {
    void visit(ObjectFoo f) {
        System.out.println("object=" + f.getValue());
    }
    void visit(IntegerFoo f) {
        System.out.println("integer=" + f.getValue());
    }
    void visit(StringFoo f) {
        System.out.println("string=" + f.getValue());
    }
}
And here is a sample code to test the implementation :
public class OOP {
    void test() {
        List<Foo> foos = Arrays.asList(new StringFoo("a String"),
                                       new StringFoo("another String"),
                                       new IntegerFoo(1),
                                       new ObjectFoo(new AtomicInteger(100)));
        DisplayVisitor visitor = new DisplayVisitor();
        for (Foo foo : foos) {
            foo.accept(visitor);
        }
    }
    public static void main(String[] args) {
        OOP oop = new OOP();
        oop.test();
    }
}
Output :
string=a String
string=another String
integer=1
object=100
Improving the implementation
The actual implementation requires the introduction of a specific wrapper class for each buit-in type we want to wrap.
As discussed, we don't have the choice to operate a double dispatch.
But note that the repeated code in Foo subclasses  could be avoided :
private Integer value; // or String or Object
@Override
public Object getValue() {
    return value;
}
We could indeed introduce a abstract generic class that holds the user value and provides an accessor to :
public abstract class Foo<T> {
    private T value;
    public Foo(T value) {
        this.value = value;
    }
    public abstract void accept(DisplayVisitor v);
    public T getValue() {
        return value;
    }
}
Now Foo sublasses are lighter to declare :
public class IntegerFoo extends Foo<Integer> {
    public IntegerFoo(Integer integer) {
        super(integer);
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
}
public class StringFoo extends Foo<String> {
    public StringFoo(String string) {
        super(string);
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
}
public class ObjectFoo extends Foo<Object> {
    public ObjectFoo(Object value) {
        super(value);
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
}
And the test() method should be modified to declare a wildcard type (?)  for the Foo type in the List<Foo> declaration.
void test() {
    List<Foo<?>> foos = Arrays.asList(new StringFoo("a String object"),
                                      new StringFoo("anoter String object"),
                                      new IntegerFoo(1),
                                      new ObjectFoo(new AtomicInteger(100)));
    DisplayVisitor visitor = new DisplayVisitor();
    for (Foo<?> foo : foos) {
        foo.accept(visitor);
    }
}
In fact, if really needed, we could simplify further Foo subclasses by introducing java code generation.
Declaring this subclass :
public class StringFoo extends Foo<String> {
    public StringFoo(String string) {
        super(string);
    }
    @Override
    public void accept(DisplayVisitor v) {
        v.visit(this);
    }
}
could as simple as declaring a class and adding an annotation on:
@Foo(String.class)
public class StringFoo { }
Where Foo is a custom annotation processed at compile time.