private void swap(List list, int i, int j){
Object o = list.get(i);
list.set(j,o);
}
这个代码看上去应该是正确的,但 Java 编译器会提示编译错误,set 语句是非法的。编译器提示我们把方法中的 List 改成 List借助带类型参数的泛型方法,这个问题可以这样解决:
private void swapInternal(List list, int i, int j) {
//...
list.set(i, list.set(j, list.get(i)));
}
private void swap(List list, int i, int j){
swapInternal(list, i, j);
}
swap 可以调用 swapInternal,而带类型参数的 swapInternal 可以写入。Java容器类中就有类似这样的用法,公共的 API 是通配符形式,形式更简单,但内部调用带类型参数的方法。
T 的消费者的意思是要操作 T,这就要求操作的容器要够大,所以容器需要是 T 的父类,即 super T;
举个例子:
private > E max(List e1){
if (e1 == null){
return null;
}
//迭代器返回的元素属于 E 的某个子类型
Iterator iterator = e1.iterator();
E result = iterator.next();
while (iterator.hasNext()){
E next = iterator.next();
if (next.compareTo(result) > 0){
result = next;
}
}
return result;
}
上述代码中的类型参数 E 的范围是 >,我们可以分步查看:
要进行比较,所以 E 需要是可比较的类,因此需要 extends Comparable<…>(注意这里不要和继承的 extends 搞混了,不一样)
Comparable< ? super E> 要对 E 进行比较,即 E 的消费者,所以需要用 super
而参数 List< ? extends E> 表示要操作的数据是 E 的子类的列表,指定上限,这样容器才够大。
Java 编辑器会将泛型代码中的类型完全擦除,使其变成原始类型。当然,这时的代码类型和我们想要的还有距离,接着 Java 编译器会在这些代码中加入类型转换,将原始类型转换成想要的类型。这些操作都是编译器后台进行,可以保证类型安全。总之泛型就是一个语法糖,它运行时没有存储任何类型信息。擦除导致的泛型不可变性。泛型中没有逻辑上的父子关系,如 List 并不是 List 的父类。两者擦除之后都是List,所以形如下面的代码,编译器会报错:
注意:这句话可能比较熟悉,没错,前面说过extend还被用来指定擦除到的具体类型,比如,表示在运行时将E替换为Fruit,注意E表示的是一个具体的类型,但是这里的extend和通配符连续使用这里通配符?表示一个通用类型,它所表示的泛型在编译的时候,被指定的具体的类型必须是Fruit的子类。比如List list= new ArrayList,ArrayList<>中指定的类型必须是Apple,Orange等。不要混淆。
概念麻烦,直接看代码:
协变泛型:
public static void playFruit(List < ? extends Fruit> list){
//do somthing
}
public static void main(String[] args) {
List apples=new ArrayList<>();
List oranges=new ArrayList<>();
List foods =new ArrayList<>();
playFruit(apples);
playFruit(oranges);
//playFruit(foods); 编译错误
}
static T[] toArray(T... args) {
return args;
}
static 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");
}
这是在《Effective Java》中看到的例子,编译此代码没有问题,但是运行的时候却会类型转换错误:Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
static Object[] toArray(Object[] args){
return args;
}
static 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
}
//和
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
}
public interface Playable {
T play();
}
public class Base implements Playable {
@Override
public Integer play() {
return 4;
}
}
public class Derived extend Base implements Playable{
...
}
当某个数据库用户在数据库中插入、更新、删除一个表的数据,或者增加一个表的主键时或者表的索引时,常常会出现ora-00054:resource busy and acquire with nowait specified这样的错误。主要是因为有事务正在执行(或者事务已经被锁),所有导致执行不成功。
1.下面的语句
insert提示IGNORE_ROW_ON_DUPKEY_INDEX
转自:http://space.itpub.net/18922393/viewspace-752123
在 insert into tablea ...select * from tableb中,如果存在唯一约束,会导致整个insert操作失败。使用IGNORE_ROW_ON_DUPKEY_INDEX提示,会忽略唯一
1.记录慢查询配置
show variables where variable_name like 'slow%' ; --查看默认日志路径
查询结果:--不用的机器可能不同
slow_query_log_file=/var/lib/mysql/centos-slow.log
修改mysqld配置文件:/usr /my.cnf[一般在/etc/my.cnf,本机在/user/my.cn
@ControllerAdvice,是spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强。让我们先看看@ControllerAdvice的实现:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Co
BW Element
OLAP Universe Element
Cube Dimension
Class
Charateristic
A class with dimension and detail objects (Detail objects for key and desription)
Hi