publicabstractclassSingletonTest<S>{/** * The singleton's getInstance method*/privatefinalSupplier<S> singletonInstanceMethod;/** * Create a new singleton test instance using the given 'getInstance' method * * @paramsingletonInstanceMethod The singleton's getInstance method*/publicSingletonTest(finalSupplier<S>singletonInstanceMethod){this.singletonInstanceMethod= singletonInstanceMethod;}/** * Test the singleton in a non-concurrent setting*/@TestpublicvoidtestMultipleCallsReturnTheSameObjectInSameThread(){ // Create several instances in the same calling threadS instance1 =this.singletonInstanceMethod.get();S instance2 =this.singletonInstanceMethod.get();S instance3 =this.singletonInstanceMethod.get(); // now check they are equalassertSame(instance1, instance2);assertSame(instance1, instance3);assertSame(instance2, instance3);}/** * Test singleton instance in a concurrent setting*/@TestpublicvoidtestMultipleCallsReturnTheSameObjectInDifferentThreads()throwsException{assertTimeout(ofMillis(10000),()->{ // Create 10000 tasks and inside each callable instantiate the singleton classfinalList<Callable<S>>tasks=newArrayList<>();for(inti=0; i <10000; i++){tasks.add(this.singletonInstanceMethod::get);} // Use up to 8 concurrent threads to handle the tasksfinalExecutorServiceexecutorService=Executors.newFixedThreadPool(8);finalList<Future<S>>results=executorService.invokeAll(tasks); // wait for all of the threads to completefinalSexpectedInstance=this.singletonInstanceMethod.get();for(Future<S>res: results){finalSinstance=res.get(); assertNotNull(instance); assertSame(expectedInstance, instance);} // tidy up the executorexecutorService.shutdown();});}}
I couldn't understand the following statement while it is indeed compilable:
Say, the second , how can we put a single in front of the method name? I suspect it's a declaration of generics but cannot find it anywhere. But I only know the definition such as List, put `` behind a generics type. Can anybody point out me a tutorial for this grammar or find the duplicated question (sorry I didn't find one during my quick search)?
Many thanks!
Ans:
This is called a type witness, and it is referenced in the Type Inference trail:
The generic method addBox defines one type parameter named U. Generally, a Java compiler can infer the type parameters of a generic method call. Consequently, in most cases, you do not have to specify them. For example, to invoke the generic method addBox, you can specify the type parameter with a type witness as follows:
Effectively, a type witness lets the developer step in to resolve cases in which the type engine can't properly infer what type a value will result in. You'd see its usage more commonly and prevalently in Java 7, whereas Java 8 has improved its type inference capabilities.
这是在《Effective Java》中看到的例子,编译此代码没有问题,但是运行的时候却会类型转换错误:Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
Supplementary characters are characters with code points in the range U+10000 to U+10FFFF, that is, those characters that could not be represented in the original 16-bit design of Unicode. The set of characters from U+0000 to U+FFFF is sometimes referred to as the Basic Multilingual Plane (BMP). Thus, each Unicode character is either in the BMP or a supplementary character.
when converting between byte[] and char[]/String or between InputStream and Reader or between OutputStream and Writer, you should always specify which encoding you want to use. If you don't, then your code will be platform-dependent.
A char represents a character in Java (*). It is 2 bytes large (at least that's what the valid value range suggests).
That doesn't necessarily mean that every representation of a character is 2 bytes long. In fact many encodings only reserve 1 byte for every character (or use 1 byte for the most common characters).
When you call the String(byte[]) constructor you ask Java to convert the byte[] to a String using the platform default encoding. Since the platform default encoding is usually a 1-byte encoding such as ISO-8859-1 or a variable-length encoding such as UTF-8, it can easily convert that 1 byte to a single character.
If you run that code on a platform that uses UTF-16 (or UTF-32 or UCS-2 or UCS-4 or ...) as the platform default encoding, then you will not get a valid result (you'll get a String containing the Unicode Replacement Character instead).
That's one of the reasons why you should not depend on the platform default encoding: when converting between byte[] and char[]/String or between InputStream and Reader or between OutputStream and Writer, you should always specify which encoding you want to use. If you don't, then your code will be platform-dependent.
(*) that's not entirely true: a char represents a UTF-16 codepoint. Either one or two UTF-16 codepoints represent a Unicode codepoint. A Unicode codepoint usually represents a character, but sometimes multiple Unicode codepoints are used to make up a single character. But the approximation above is close enough to discuss the topic at hand.
public class EnumIvoryTowerTest extends SingletonTest<EnumIvoryTower> {
/**
* Create a new singleton test instance using the given 'getInstance' method
*/
public EnumIvoryTowerTest() {
super(() -> EnumIvoryTower.INSTANCE);
}
}
public interface WeaponFactory {
/**
* Creates an instance of the given type.
* @param name representing enum of an object type to be created.
* @return new instance of a requested class implementing {@link Weapon} interface.
*/
Weapon create(WeaponType name);
/**
* Creates factory - placeholder for specified {@link Builder}s.
* @param consumer for the new builder to the factory.
* @return factory with specified {@link Builder}s
*/
static WeaponFactory factory(Consumer<Builder> consumer) {
Map<WeaponType, Supplier<Weapon>> map = new HashMap<>();
consumer.accept(map::put); //map::put是对Builder add的实现
return name -> map.get(name).get(); //返回对WeaponFactory create方法的实现
}
}
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {
WeaponFactory factory = WeaponFactory.factory(builder -> {//传入Consumer Accept的实现,传入的不是数据而是函数式接口 void accept(Builder)
builder.add(WeaponType.SWORD, Sword::new);
builder.add(WeaponType.AXE, Axe::new);
builder.add(WeaponType.SPEAR, Spear::new);
builder.add(WeaponType.BOW, Bow::new);
});
Weapon axe = factory.create(WeaponType.AXE);
LOGGER.info(axe.toString());
}
}
public interface Builder {
void add(WeaponType name, Supplier<Weapon> supplier);
}
自己试的
public interface Fruit {
public static void main(String[] args) {
System.out.println("asdasd");
Consumer<Builder> c = builder -> {
builder.add();
builder.add();
builder.add();
builder.add();
};
}
public interface Builder {
void add();
}
}
List<Integer> l = Collections.<Integer>singletonList(5);
List<Integer> l = Collections.<Integer>singletonList(5);
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
static <T> T[] toArray(T... args) {
return args;
}
static <T> T[] pickTwo(T a, T b, T c) {
switch(ThreadLocalRandom.current().nextInt(3)) {
case 0: return toArray(a, b);
case 1: return toArray(a, c);
case 2: return toArray(b, c);
}
throw new AssertionError(); // Can't get here
}
public static void main(String[] args) {
String[] attributes = pickTwo("Good", "Fast", "Cheap");
}Copy to clipboardErrorCopied
static Object[] toArray(Object... args){
return args;
}Copy to clipboardErrorCopied
static Object[] toArray(Object[] args){
return args;
}
static <T> T[] pickTwo(T a, T b, T c) {
switch(ThreadLocalRandom.current().nextInt(3)) {
case 0: return toArray(a, b);
case 1: return toArray(a, c);
case 2: return toArray(b, c);
}
throw new AssertionError(); // Can't get here
}Copy to clipboardErrorCopied
static Object[] pickTwo(Object a, Object b, Object c) {
switch(ThreadLocalRandom.current().nextInt(3)) {
case 0: return toArray(new Object[]{a,b});//可变参数会根据调用类型转换为对应的数组,这里a,b,c都是Object
case 1: return toArray(new Object[]{a,b});
case 2: return toArray(new Object[]{a,b});
}
throw new AssertionError(); // Can't get here
}Copy to clipboardErrorCopied
public static void main(String[] args) {
String[] attributes =(String[])pickTwo("Good", "Fast", "Cheap");
}Copy to clipboardErrorCopied