黑马程序员

xiaoxiao2021-03-01  13

----------- [url=http://www.itheima.com]android培训[/url]、[url=http://www.itheima.com]java培训[/url]、java学习型技术博客、期待与您交流! ------------ [b]线程显示锁机制[/b] jdk1.5后Lock可以替代Synchronized Conditioin对象封装了wait、notify、notifyAll同步方法 显示锁机制 1.生成锁 Lock lock = new ReentrantLock();一个锁可以对应多个Condition对象对不同线程状态进行控制。 2.持有锁 lock.lock();在方法中使用lock方法对方法加锁 3.同步Condition con = lock.newCondition(); con.await();...... 4.释放锁lock.unclock(); Lock lock = new ReentrantLock();Condition thread1 = lock.newConditon();Condition thread2 = lock.newCondition();public void method(){ lock.lock(); //......... lock.unlock();} [b]可变参数[/b] 方法接受的参数个数不固定 格式 方法(参数类型 ... 变量名){} 举例 public void func(int... args){ for(int arg:args) System.out.println(arg);} 可变参数的特点: 1.省略符号位于变量类型和变量名之间,空格可有可无。 2.可变参数只能出现在参数列表最后 3.编译器为可变参数隐式的创建了一个数组,在方法中以数组的形式访问可变参数的。 [b]静态导入[/b] 要使用其他包中类的静态方法时,需要用类名调用。 使用静态导入后可以不写类名直接调用类的静态方法。 格式: import static 包名.类名.方法名;导入类中指定的静态方法 import static 包名.类名.*;导入类中所有静态方法。 import static java.lang.Math.*;public class StaticImport{ public static void main(String[] args) { int max = max(1,2);//静态导入可以省略前缀名Math System.out.println(max); }}[b] [/b] [b]增强for循环格式[/b] for(type 变量名:集合变量名) { ……; } 增强for循环特点 1.变量必须在()括号内定义 2.集合可以是是数组或可迭代的集合(实现了iterable接口的集合)。 另外变量前面也可以添加修饰符 int[] elements = {1,2,3};for(int element : elements){ System.out.println(element);} [b]java基本数据类型的自动装箱与拆箱。[/b] 自动装箱 如果一个表达式的值类型为基本数据类型,当把这个值赋值给它的包装类型变量时,java虚拟机会把这个值自动装箱成它的包装类型并赋值。 Integer inter = 1+2;//将1+2的值自动装箱成Integer在赋值给inter 自动拆箱 如果一个表达式的值类型为基本数据类型的包装类类型,当把这个值赋值给它的基本数据类型变量时,java虚拟机会把这个值自动拆箱成它的基本数据类型并赋值。 Integer inter = 1+2;//将1+2的值自动装箱成Integer在赋值给interint temp = inter;//将inter自动拆箱为int类型在赋值给temp 自动装箱和拆箱的享元模式flyweight 当创建Integer对象时,如果这个对象的int值在一个字节之内,就会把这个对象缓存起来,下次创建Integer对象时如果已经存在这样值的对象就不会在重新创建对象,它们共享同一个对象。 把具有相同的属性的小的对象变成同一个对象,把那些不同属性的对象作为外部属性作为方法参数传入称为外部状态,相同属性称为内部状态。这就是享元模式。 [b]枚举[/b] 枚举就是对固定数量的一类事物的描述。 枚举可以让编译器检查源程序中出现的枚举类型值的合法性。 枚举的值只能是枚举类中的元素,否则编译失败。 枚举类 1.通过enum关键字定义枚举类,但不可以继承Enum类来定义枚举类。 2.枚举元素列表必须放在其他成员最前面定义。 3.每个元素默认都是public static final类型的常量,但不能显示添加修饰符,因为是常量所以元素名用大 写字母表示。 4.枚举类构造方法必须是私有的,加载枚举类时调用构造函数对元素进行初始化,通过枚举常量后面的括号中 的参数确定这些元素在初始化的时候调用哪个构造函数,。 5.可以有若干个公有的普通方法或抽象方法,元素列表中的元素必须实现枚举类中的抽象方法。 6.枚举类只有一个元素时,可以作为一种单例设计模式。 带有抽象方法的枚举类 /* 交通灯枚举类 */ public enum TrafficTamp { GREEN { public TrafficTamp nextTamp() { return YELLOW; } }, YELLOW { public TrafficTamp nextTamp() { return GREEN; } }, RED { public TrafficTamp nextTamp() { return GREEN; } }; public abstract TrafficTamp nextTamp(); } [b]注解[/b] @Overridepublic String toString(){ return name+"::"+age;} 什么是注解? 注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类以及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。 java.lang包提供了三种注解类型,Deprecated,Override,SuppressWarning。 注解的定义与反射调用 [img]http://dl.iteye.com/upload/attachment/0079/5606/35b78ebe-c539-388f-b4a0-8194bb2ba33f.bmp[/img] 注解类的生命周期 有三种情况,由枚举类RetentionPolicy中的三个元素决定RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME。 默认是RetentionPolicy.Class Override:RetentionPolicy.SOURCE SuppressWarning:RetentionPolicy.RUNTIME 所以,在自定义注解类时,要使它的生命周期一直保留到运行时期,需要在注解类中添加@Rentention(RetentionPolicy.RUNTIME)注解。 注解目标Target /*注解可以加在方法上,也可以加在类上*/ @Target({ElementType.METHOD,ElementType.TYPE}) public @interface ItcastAnnotation { } 为注解增加属性 什么是注解的属性? 一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则就不是。如果还想区分出是传智播客哪个班的学生,这时候可以为胸牌在添加属性类区分。加了属性的标记效果:@MyAnnotation(color=”red”); 定义基本类型的属性和应用属性 1. 在注解类中增加 String color(); 2. @MyAnnotation(color=”red”); 通过反射方式获取注解对应的实例对象后,在通过对象调用对应的方法 MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class); System.out.println(a.color); 可以认为上面这个@MyAnnotation是MyAnnotation类的一个实例对象 为属性指定缺省值 String color() default “yellow”; value属性 String value() default “zzz”; 如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或你只有一个value属性),那么可以省略value=部分,例如@MyAnnotation(“hzd”); 为注解类添加高级属性 数组类型的属性 int[] arrayAttr() default{1,2,3}; @MyAnnotation(arrAttr={2,3,4}); 枚举类型的属性 EnumTest.TrafficLamp lamp(); @MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN); 注解类型的属性 MetaAnnotation annotationAttr() default @MetaAnnotation(“xxx”); @MyAnnotation(annotationAttr=@MetaAnnotation(“yyy”)); 代码示例: 注解类ItcastAnnotation package cn.itcast.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.util.concurrent.TimeUnit;/** * 注解类ItcastAnnotation * @author hezhudong * *//*注解生命周期*/@Retention(RetentionPolicy.RUNTIME)/*注解可以加在方法上,也可以加在类上*/@Target({ElementType.METHOD,ElementType.TYPE})public @interface ItcastAnnotation { /*注解的属性*/ String color() default "blue"; int[] arrayAttr() default{3,4,4}; String value(); TimeUnit timeUnit() default TimeUnit.SECONDS; MetaAnnotation annotationAttr()default @MetaAnnotation("zxx");} 注解类MetaAnnotation package cn.itcast.annotation;/** * 注解类MetaAnnotation * @author hezhudong * */public @interface MetaAnnotation { /*注解的属性*/ String value();} 注解测试类AnnotationTest package cn.itcast.annotation;import java.util.concurrent.TimeUnit;/** * 注解测试类AnnotationTest * @author hezhudong * *///加入注解,并为注解属性设置属性值@ItcastAnnotation(annotationAttr=@MetaAnnotation("zxx"),timeUnit=TimeUnit.HOURS,color="red",value = "hzd",arrayAttr=1)public class AnnotationTest { @ItcastAnnotation("hzd")//只有一个value属性需要设置的时候可以省略value= public static void main(String[] args) { /*AnnotationTest字节码中是否有ItcastAnnotation类型的注解*/ if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)) { ItcastAnnotation annotation = AnnotationTest.class.getAnnotation(ItcastAnnotation.class); //打印注解对象annotation的属性值 System.out.println(annotation.color()); System.out.println(annotation.value()); System.out.println(annotation.arrayAttr().length); System.out.println(annotation.timeUnit()); System.out.println(annotation.annotationAttr()); } }} [b]泛型[/b] 由问题引出泛型 JDk1.5的集合中存在的问题? ArrayList collection = new ArrayList(); collection.add(1); collection.add(lL); collection.add(“abc”); int i = (Integer)collection.get(2);//编译要求强制类型转换且运行时错误。类型转换异常。 Jdk1.5的集合希望你在定义集合时,明确表示要向集合中添加那种类型的元素,无法加入指定类型以外的数据。 ArrayList<Integer> collection = new ArrayList<Integer>(); collection.add(1); collection.add(lL);//编译失败,不能添加Integer类型以外的类型 collection.add(“abc”); //编译失败,不能添加Integer类型以外的类型 int i = collection.get(0);//不需要进行强制类型转换 什么是泛型? 泛型是一种安全机制,让编译器检查要存储到集合中的元素类型是否合法,将问题由运行时期转移到了编译时期,提高了安全性。 泛型扩展: 在jdk1.5中如果集合没有使用泛型编译器会包括unchecked警告。编译器编译带有类型说明的集合时会去除掉“类型”信息,使程序运行效率不受到影响,对于参数化的的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译器生产的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往集合中添加其他类型的元素,例如,用反射获取集合,在调用add方法即可。 通过反射向泛型类型的集合中添加类型参数指定类型以外的元素 代码示例: package cn.itcast.generic;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Collection;/** * 泛型测试类 * 测试通过反射向使用泛型的集合中添加其他类型的元素 * @author hezhudong * */public class GenericTest { /** * @param args */ public static void main(String[] args) throws Exception{ //创建一个泛型类型的集合,集合元素类型为Integer,向其中添加一个Integer对象 ArrayList<Integer> collection = new ArrayList<Integer>(); collection.add(1); //通过反射获取到集合对象,向集合中添加一个非Integer类型的元素,并获取打印 Class clazz = collection.getClass(); Method methodAdd = clazz.getMethod("add", Object.class); methodAdd.invoke(collection, "hzd"); System.out.println(collection.get(1)); }} ArrayList<E>类定义和ArrayList<Integer>类引用中涉及以下术语: 1. 整个称为ArrayList<E>泛型类型 2. ArrayList<E>中的E成为类型变量或类型参数 3. 整个ArrayList<Integer>成为参数化的类型 4. ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数 5. ArrayList<Integer>中的<>念做typeof 6. ArrayList称为原始类型 参数化类型与原始类型的兼容性 1. 参数化类型可以引用一个原始类型的对象,编译报告警告,例如: Collection<String> c = new Vector(); 2 原始类型可以引用一个参数化的类型的对象,编译报告错误,例如: Collection c = new Vector<String> (); 3 参数化类型不考虑类型参数的继承关系 Vector<String> v = new Vector<Object>();//编译报告错误 Vector< Object > v = new Vector< String >();//编译也错误 4…..编译器也不允许创建类型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型,例如: Vector<Integer> vectorList[] = new Vector< String >()[10]; //编译报告错误 泛型通配符扩展引用 泛型中的?通配符 使用?通配符可以引用其他任意参数化的类型,?通配符定义的变量主要用做引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。 代码示例: public static void printGenericCollection(Collection<?> cols) { System.out.println(cols.size());//不会报错,此方法与类型参数没有关系 System.out.println(cols.add(1));//会报错,因为不确定将要匹配的一定是Integer for(Object obj : cols) { System.out.println(obj); } } ?通配符的泛型限定 限定通配符的上边界: Vector<? extends Number> v = new Vector<Integer>();//正确,参数化类型是Number或它的子类 Vector<? extends Number> v = new Vector<String>();//错误,String不是Number或Number的子类 限定通配符的下边界: Vector<? super Integer> vector = new Vector<Number>();//正确,参数化类型是Integer或它的父类 Vector<? super Integer> vector = new Vector<Byte>();//错误,Byte不是Integer或它的父类 自定义泛型 Java泛型类型类似于C++中的模板,但是这种相似性仅局限于表面,java语言中的泛型基本上完全是在编译中实现,用于编译器执行类型检查和类型推断,然后生成普通的非泛型字节码,这种实现技术成为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其擦除)。这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会使java厂商升级其JVM造成难以逾越的障碍。所以,java的泛型采用了可以完全在编译器重实现的擦除方法。 下面方法会报错,对于T类型的x和y提示操作符+号没有被定义,这也体现了java泛型没有C++模板功能强大 <T> T add(T x,T y) { return (T)(x+y); } 自定义泛型的使用 1. 用于放置泛型的类型参数的尖括号应出现在其他所有修饰符之后和在方法的返回值之前,也就是紧邻返回值之前。按照惯例,类型参数通常用大写字母表示。 2. 只有引用类型才能作为泛型方法的实际参数,swap(new int[3],3,5);会报告编译错误。 3. 除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,如<V extends Serializable&cloneable> void method(){} 4. 普通方法、构造方法和静态方法中都可以使用泛型。编译器也不允许创建类型变量的数组。 5. 也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch语句中。 6. 在泛型中可以同时又多个类型参数,在定义它们的尖括号中用逗号分隔开,例如 public static <K,V> V getValue(K key){return map.get(key);} . 代码示例:使用泛型交换两个数组中的元素值 static<T> void swap(T[] arr,int x,int y) { T t = arr[x]; arr[x] = arr[y]; arr[y] = t; } 类型参数的类型推断 编译器判断泛型方法的实际参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种非常复杂的过程。 根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下: 1. 当某个类型变量只在整个参数列表中的所有参数和返回值的一处被应用了,那么根据调用方法时该处的实际类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来确定泛型参数的类型,例如 swap(new String[3],3,4)static <E> void swap(E[],int i,int j); 2. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时该处的实际应用类型都对应同一种类型来确定,这很容易凭感觉推断出来,例如 add(3,5)static <T> T add(T a, T b) 3. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同类型,且没有返回值,这时候取多个参数中的最大交集类型,例如下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题。 fill(new Integer[3],3.5f)static <T> void fill(T[] a,T v); 4. 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同类型,并且使用返回值,这时优先考虑返回值的类型,例如下面语句实际对应的类型就是Integer了,编译器将报告错误,将变量x的类型改为float,对比eclipse报告的错误提示,接着在讲x改为Number,则没有错误 int x = add(3,3.5f) static <T> T add(T a, T b) 5. 参数类型的类型推断具有传递性,下面第一种情况推断实际类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题。 copy(new Integer[5],new String[5])static <T> void copy(T[] a,T[] b) 通过反射获取泛型的实际类型参数 因为泛型在编译时类型信息会被擦除,所以我们无法直接获取泛型的实际类型参数属于哪种类型,但是Method类有一个方法Type[] getGenericParameterTypes()方法获取泛型参数的类型(比如Vector<Integer> v 参数泛型参数类型就是Vector),在通过Type对象的Type[] getActualTypeArguments()方法获取实际类型参数,因此,将泛型类型作为方法参数时,可以获取其实际类型参数。 代码示例 /* * 带有参数化类型的参数 */ public static void genericParameter(Vector<Date> v) { } //获取genericParameter方法 Method methodGeneric = GenericTest.class.getMethod("genericParameter", Vector.class); //获取参数化的类型参数 ParameterizedType type = (ParameterizedType)methodGeneric.getGenericParameterTypes()[0]; //获取参数化类型参数的实际类型参数,并打印 String argType = type.getActualTypeArguments()[0].toString(); System.out.println(argType);; ----------- [url=http://www.itheima.com]android培训[/url]、[url=http://www.itheima.com]java培训[/url]、java学习型技术博客、期待与您交流! ------------ 相关资源:Java 面经手册·小傅哥(公众号:bugstack虫洞栈).pdf
转载请注明原文地址: https://www.6miu.com/read-3200191.html

最新回复(0)