查看: 1502|回复: 1

[Java语言] Java基础提高

发表于 2017-8-9 08:00:01
句号论坛

这是传智张孝祥老师Java诚聘技术的授课笔记
我认为讲的很棒,授课传送门如下:
Java诚聘技术

一、枚举 1.基本应用
  1. public class Test {
  2. public static void main(String[] args) {
  3. WeekDay day1=WeekDay.FRI;
  4. System.out.println(day1.name());
  5. System.out.println(day1.ordinal());
  6. System.out.println(WeekDay.valueOf("SUN"));
  7. }
  8. }
  9. enum WeekDay{
  10. SUN,MON,TUE,WED,THU,FRI,SAT;
  11. }
复制代码
2.带有构造方法的枚举
  1. public class Test {
  2. public static void main(String[] args) {
  3. WeekDay day1=WeekDay.FRI;
  4. System.out.println(day1.name());
  5. System.out.println(day1.ordinal());
  6. System.out.println(WeekDay.valueOf("SUN"));
  7. }
  8. }
  9. enum WeekDay{
  10. SUN(1),MON,TUE,WED,THU,FRI,SAT;
  11. private WeekDay(){//枚举类的静态变量在枚举被加载的时候就会创建,并且只能用私有修饰
  12. System.out.println("none parameter");
  13. }
  14. private WeekDay(int i){
  15. System.out.println("parameter:"+i);
  16. }
  17. }
复制代码
3.带有抽象方法的枚举
  1. public class Test {
  2. public static void main(String[] args) {
  3. }
  4. }
  5. enum TrafficLamp{
  6. RED(30) {
  7. @Override
  8. TrafficLamp nextLamp() {
  9. return GREEN;
  10. }
  11. },GREEN(45) {
  12. @Override
  13. TrafficLamp nextLamp() {
  14. return YELLOW;
  15. }
  16. },YELLOW(5) {
  17. @Override
  18. TrafficLamp nextLamp() {
  19. return RED;
  20. }
  21. };
  22. abstract TrafficLamp nextLamp();
  23. private int time;
  24. private TrafficLamp(int time){
  25. this.time=time;
  26. }
  27. }
复制代码
二、反射 1.Class类

在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
获得class对象的方法有三种

  1. Class c1=Date.class;
  2. Class c2=new Date().getClass();
  3. Class c3=Class.forName("java.util.Date");
  4. System.out.println(c1==c2);
  5. System.out.println(c1==c3);
复制代码

public boolean isPrimitive()判定指定的 Class 对象是否表示一个基本类型。
有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。 这些对象仅能通过下列声明为 public static final 的变量访问,也是使此方法返回 true 的仅有的几个 Class 对象。

  1. public class Test {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. Class c1=Date.class;
  4. Class c2=int.class;
  5. Class c3=Integer.class;
  6. Class c4=Integer.TYPE;
  7. System.out.println(c1.isPrimitive());
  8. System.out.println(c2.isPrimitive());
  9. System.out.println(c3.isPrimitive());
  10. System.out.println(c4.isPrimitive());
  11. System.out.println(c2==c3);
  12. System.out.println(c2==c4);
  13. Class c5=int[].class;
  14. System.out.println(c5.isPrimitive());
  15. System.out.println(c5.isArray());
  16. }
  17. }
复制代码
2.反射

反射就是把类中的各种成分映射成相应的类,比如把“方法”映射成Method类,把“成员变量”映射成Field类等等

2.1 构造方法的反射应用

  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. Constructor constructor1=String.class.getConstructor(StringBuffer.class);//要是用类型
  4. String str2=(String)constructor1.newInstance(new StringBuffer("abc"));//要使用之前类型相同的对象
  5. System.out.println(str2);
  6. String str2=(String)Class.forName("java.lang.String").newInstance();//使用默认的构造方法
  7. }
  8. }
复制代码

2.2 成员变量的反射应用

“人有身高这一属性”与“我有身高这一属性不同”,也与“我的身高是XXX”不同

  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. Person me=new Person(180,140);
  4. Field height_field=Person.class.getField("height");
  5. //height_field指的是取得了Person这个类所具有的一个属性,即身高这样一个属性,并不是取得的某个人的实际身高
  6. System.out.println(height_field.get(me));
  7. Field weight_field=Person.class.getDeclaredField("weight");
  8. weight_field.setAccessible(true);
  9. System.out.println(weight_field.get(me));
  10. }
  11. }
  12. class Person{
  13. public int height;
  14. private int weight;
  15. public Person(int height, int weight) {
  16. super();
  17. this.height = height;
  18. this.weight = weight;
  19. }
  20. }
复制代码

修改某一对象中的成员变量举例:

  1. import java.lang.reflect.Field;
  2. public class Test {
  3. public static void main(String[] args) throws Exception{
  4. ReflectPoint pt1=new ReflectPoint(3,5);
  5. Field[] fields=ReflectPoint.class.getFields();
  6. for (Field field : fields) {
  7. if(field.getType()==String.class){
  8. String oldValue=(String)field.get(pt1);
  9. String newValue=oldValue.replace("b", "a");
  10. field.set(pt1, newValue);
  11. }
  12. }
  13. System.out.println(pt1);
  14. }
  15. }
  16. class ReflectPoint{
  17. public ReflectPoint(int x, int y) {
  18. super();
  19. this.x = x;
  20. this.y = y;
  21. }
  22. private int x;
  23. public int y;
  24. public String str1="ball";
  25. public String str2="basketball";
  26. public String str3="itcast";
  27. @Override
  28. public String toString() {
  29. return "ReflectPoint [x=" + x + ", y=" + y + ", str1=" + str1 + ", str2=" + str2 + ", str3=" + str3 + "]";
  30. }
  31. }
复制代码

2.3 成员方法的反射

基本应用
“人有跳的能力”与“我有跳的能力”不一样

  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. Method methodCharAt=String.class.getMethod("charAt", int.class);//后面指的是传入的参数
  4. //同样,这取得的是String类的这样一个方法,是一种属性,而不是某个对象的成员方法
  5. System.out.println(methodCharAt.invoke("abcde", 1));
  6. //someMethod.invoke(null,parameter)指的是调用的静态方法
  7. }
  8. }
复制代码

应用:
目标:写一个程序,这个程序能够根据用户提供的类名,去调用类方法

  1. import java.lang.reflect.Method;
  2. public class Test {
  3. public static void main(String[] args) throws Exception{
  4. // TestArguments.main(new String[]{"111","222","333"});
  5. String startingClassName=args[0];
  6. Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);
  7. mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
  8. /* 如果没有类型转换会出现problems
  9. * Type String[] of the last argument to method invoke(Object, Object...)
  10. * doesn't exactly match the vararg parameter type. Cast to Object[] to confirm the non-varargs invocation,
  11. * or pass individual arguments of type Object for a varargs invocation.
  12. */
  13. }
  14. }
  15. class TestArguments{
  16. public static void main(String[] args) {
  17. for (String string : args) {
  18. System.out.println(string);
  19. }
  20. }
  21. }
复制代码

要修改run configuration

2.4 数组与Object的关系及其反射类型
维度与类型同时相同时,得到的class即相同

  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. int[] a0=new int[3];
  4. int[] a1=new int[3];
  5. int[] a2=new int[4];
  6. System.out.println(a0.getClass()==a1.getClass());
  7. System.out.println(a1.getClass()==a2.getClass());
  8. System.out.println(a1.getClass().getName());
  9. }
  10. }
复制代码

2.5 数组的反射应用
举例

  1. public class Test {
  2. public static void main(String[] args) throws Exception{
  3. printObject(new String[]{"a","b","c"});
  4. printObject("xyz");
  5. }
  6. private static void printObject(Object obj) {
  7. Class c=obj.getClass();
  8. if(c.isArray()){
  9. int len=Array.getLength(obj);
  10. for(int i=0;i<len;i++){
  11. System.out.println(Array.get(obj, i));
  12. }
  13. }else{
  14. System.out.println(obj);
  15. }
  16. }
  17. }
复制代码

2.6 ArrayList_HashSet的比较及Hashcode分析

先比较hashcode如果hashcode相同,则运行equels方法,两者同时相等时,则认定为相同对象,如果之后修改了参与运算hashcode的成员变量,则会造成内存溢出,如下例子中remove会失效

  1. import java.util.HashSet;
  2. public class Test {
  3. public static void main(String[] args) throws Exception{
  4. HashSet<TestArguments> set=new HashSet<>();
  5. TestArguments t1=new TestArguments(3);
  6. TestArguments t2=new TestArguments(3);
  7. set.add(t1);
  8. set.add(t2);
  9. System.out.println(set.size());
  10. t1.x=456;
  11. set.remove(t1);
  12. System.out.println(set.size());
  13. }
  14. }
  15. class TestArguments{
  16. int x;
  17. public TestArguments(int x) {
  18. super();
  19. this.x = x;
  20. }
  21. @Override
  22. public int hashCode() {
  23. final int prime = 31;
  24. int result = 1;
  25. result = prime * result + x;
  26. return result;
  27. }
  28. @Override
  29. public boolean equals(Object obj) {
  30. if (this == obj)
  31. return true;
  32. if (obj == null)
  33. return false;
  34. if (getClass() != obj.getClass())
  35. return false;
  36. TestArguments other = (TestArguments) obj;
  37. if (x != other.x)
  38. return false;
  39. return true;
  40. }
  41. }
复制代码
3.反射的作用——实现框架功能

框架
现在使用别人写的类的时候,有两种使用方式,一种是用户去使用别人的类(工具),另一种是别人的类去调用用户写的类(框架)。再打个比方:比如我做房子卖给用户居住,由用户自己安装门窗和空调,我制作的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架之中,即用户的门窗被房子调用,这就是框架。

框架要解决的核心问题
在写框架的时候并不知道用户要写的类名,所以框架中不能直接new某个类的实例对象,因此只能通过反射来做

代码举例

  1. import java.io.FileInputStream;
  2. import java.io.InputStream;
  3. import java.util.Collection;
  4. import java.util.Properties;
  5. public class Test {
  6. public static void main(String[] args) throws Exception{
  7. InputStream ips=new FileInputStream("config.properties");
  8. Properties props=new Properties();
  9. props.load(ips);
  10. ips.close();
  11. String className=props.getProperty("className");
  12. @SuppressWarnings("unchecked")
  13. Collection<ReflectPoint> collection=(Collection<ReflectPoint>)Class.forName(className).newInstance();
  14. ReflectPoint pt1=new ReflectPoint(3,3);
  15. ReflectPoint pt2=new ReflectPoint(5,5);
  16. ReflectPoint pt3=new ReflectPoint(3,3);
  17. collection.add(pt1);
  18. collection.add(pt2);
  19. collection.add(pt3);
  20. System.out.println(collection.size());
  21. }
  22. }
复制代码

config.properties文件内容为

className=java.util.ArrayList

3.1 管理配置文件的方式

  1. import java.io.FileInputStream;
  2. import java.io.InputStream;
  3. import java.util.Collection;
  4. import java.util.Properties;
  5. public class Test {
  6. public static void main(String[] args) throws Exception{
  7. // InputStream ips=new FileInputStream("config.properties");
  8. //以下的配置文件路径应该与该类的Java文件放在同一目录
  9. // InputStream ips=ReflectPoint.class.getResourceAsStream("config.properties");
  10. InputStream ips=ReflectPoint.class.getClassLoader().getResourceAsStream("zheteng/config.properties");
  11. Properties props=new Properties();//此方法首先搜索资源的父类加载器;如果父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。
  12. props.load(ips);
  13. ips.close();
  14. String className=props.getProperty("className");
  15. @SuppressWarnings("unchecked")
  16. Collection<ReflectPoint> collection=(Collection<ReflectPoint>)Class.forName(className).newInstance();
  17. ReflectPoint pt1=new ReflectPoint(3,3);
  18. ReflectPoint pt2=new ReflectPoint(5,5);
  19. ReflectPoint pt3=new ReflectPoint(3,3);
  20. collection.add(pt1);
  21. collection.add(pt2);
  22. collection.add(pt3);
  23. System.out.println(collection.size());
  24. }
  25. }
  26. class ReflectPoint{
  27. public ReflectPoint(int x, int y) {
  28. super();
  29. this.x = x;
  30. this.y = y;
  31. }
  32. private int x;
  33. public int y;
  34. @Override
  35. public int hashCode() {
  36. final int prime = 31;
  37. int result = 1;
  38. result = prime * result + x;
  39. result = prime * result + y;
  40. return result;
  41. }
  42. @Override
  43. public boolean equals(Object obj) {
  44. if (this == obj)
  45. return true;
  46. if (obj == null)
  47. return false;
  48. if (getClass() != obj.getClass())
  49. return false;
  50. ReflectPoint other = (ReflectPoint) obj;
  51. if (x != other.x)
  52. return false;
  53. if (y != other.y)
  54. return false;
  55. return true;
  56. }
  57. }
复制代码
4.JavaBean

JavaBean是特殊的Java类,使用java语言书写,并且遵守JavaBean API规范。
接下来给出的是JavaBean与其它Java类相比而言独一无二的特征:

提供一个默认的无参构造函数。

需要被序列化并且实现了Serializable接口。

可能有一系列可读写属性。

可能有一系列的"getter"或"setter"方法。

Java bean 是个什么概念? - 回答作者: 杨博 通俗易懂

我认为,JavaBean的存在就是为了让类中的属性能更方便地被处理和提取

4.1 JavaBean的简单操作

  1. import java.beans.PropertyDescriptor;
  2. import java.lang.reflect.Method;
  3. public class Test {
  4. public static void main(String[] args) throws Exception {
  5. ReflectPoint pt1 = new ReflectPoint(3, 5);
  6. String propertyName = "x";
  7. PropertyDescriptor pd = new PropertyDescriptor(propertyName, ReflectPoint.class);
  8. Method methodGetX = pd.getReadMethod();
  9. Object retVal = methodGetX.invoke(pt1);
  10. System.out.println(retVal);
  11. Method methodSetX = pd.getWriteMethod();
  12. methodSetX.invoke(pt1, 7);
  13. System.out.println(pt1.getX());
  14. }
  15. }
  16. class ReflectPoint {
  17. public ReflectPoint(int x, int y) {
  18. super();
  19. this.x = x;
  20. this.y = y;
  21. }
  22. private int x;
  23. private int y;
  24. public int getX() {
  25. return x;
  26. }
  27. public void setX(int x) {
  28. this.x = x;
  29. }
  30. public int getY() {
  31. return y;
  32. }
  33. public void setY(int y) {
  34. this.y = y;
  35. }
  36. }
复制代码

4.2 BeanUtils工具包操作JavaBean
需要BeanUtils与common.logging包

举例1:

  1. import org.apache.commons.beanutils.BeanUtils;
  2. import org.apache.commons.beanutils.PropertyUtils;
  3. public class Test {
  4. public static void main(String[] args) throws Exception {
  5. ReflectPoint pt1 = new ReflectPoint(3, 5);
  6. System.out.println(BeanUtils.getProperty(pt1, "x"));
  7. System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());
  8. BeanUtils.setProperty(pt1, "x", "9");//以string的形式对javabean进行操作
  9. System.out.println(pt1.getX());
  10. BeanUtils.setProperty(pt1, "birthday.time", 111);
  11. System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
  12. PropertyUtils.setProperty(pt1, "x", 9);//以属性本身的类型的形式对javabean进行操作
  13. System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());
  14. }
  15. }
复制代码

其中ReflectPoint为

  1. import java.util.Date;
  2. public class ReflectPoint {
  3. public ReflectPoint(int x, int y) {
  4. super();
  5. this.x = x;
  6. this.y = y;
  7. this.birthday = new Date();
  8. }
  9. private int x;
  10. private int y;
  11. private Date birthday;
  12. public int getX() {
  13. return x;
  14. }
  15. public void setX(int x) {
  16. this.x = x;
  17. }
  18. public int getY() {
  19. return y;
  20. }
  21. public void setY(int y) {
  22. this.y = y;
  23. }
  24. public Date getBirthday() {
  25. return birthday;
  26. }
  27. public void setBirthday(Date birthday) {
  28. this.birthday = birthday;
  29. }
  30. }
复制代码
三、注解 1.了解注解

1.1 @Deprecated

  1. public class AnnotationTest {
  2. public static void main(String[] args) {
  3. sayHello();
  4. }
  5. @Deprecated
  6. public static void sayHello(){
  7. System.out.println("hello!SF.GG!");
  8. }
  9. }
复制代码

1.2 @Override

  1. @Override
  2. public String toString() {
  3. return "AnnotationTest []";
  4. }
复制代码
2.注解的定义与反射调用
  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Retention;
  3. import java.lang.annotation.RetentionPolicy;
  4. import java.lang.annotation.Target;
  5. @MyAnnotation
  6. public class AnnotationTest {
  7. public static void main(String[] args) {
  8. sayHello();
  9. if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
  10. MyAnnotation myannotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
  11. System.out.println(myannotation);
  12. }
  13. }
  14. @Deprecated
  15. public static void sayHello(){
  16. System.out.println("hello!SF.GG!");
  17. }
  18. }
  19. @Retention(RetentionPolicy.RUNTIME)
  20. @Target({ElementType.METHOD,ElementType.TYPE})
  21. @interface MyAnnotation{
  22. }
复制代码
3.为注解增加各种属性

看起来注解就是为了方便为自定义的类打上一些标签的作用

  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Retention;
  3. import java.lang.annotation.RetentionPolicy;
  4. import java.lang.annotation.Target;
  5. @MyAnnotation(color = "red", value = "abc", arrayValue = 1,annotationAttr=@MetaAnnotation("flx"))
  6. public class AnnotationTest {
  7. @MyAnnotation("xyz") // 当只有一个value属性需要赋值的时候,可以不用写value
  8. public static void main(String[] args) {
  9. sayHello();
  10. if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
  11. MyAnnotation myannotation = (MyAnnotation) AnnotationTest.class.getAnnotation(MyAnnotation.class);
  12. System.out.println(myannotation.color());
  13. System.out.println(myannotation.value());
  14. System.out.println(myannotation.arrayValue().length);
  15. System.out.println(myannotation.trafficLamp().next());
  16. System.out.println(myannotation.annotationAttr().value());
  17. }
  18. }
  19. @Deprecated
  20. public static void sayHello() {
  21. System.out.println("hello!SF.GG!");
  22. }
  23. }
  24. @Retention(RetentionPolicy.RUNTIME)
  25. @Target({ ElementType.METHOD, ElementType.TYPE })
  26. @interface MyAnnotation {
  27. String color() default "blue";
  28. String value();
  29. int[] arrayValue() default { 3, 4, 4 };
  30. Lamp trafficLamp() default Lamp.RED;
  31. MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");
  32. }
  33. @interface MetaAnnotation {
  34. String value();
  35. }
  36. enum Lamp {
  37. RED, YELLOW, GREEN;
  38. Lamp next() {
  39. if (this.equals(RED)) {
  40. return GREEN;
  41. }
  42. if (this.equals(GREEN)) {
  43. return YELLOW;
  44. } else {
  45. return RED;
  46. }
  47. }
  48. }
复制代码
四、泛型 1.基本应用
  1. import java.lang.reflect.Constructor;
  2. import java.util.ArrayList;
  3. public class Test {
  4. public static void main(String[] args) throws Exception {
  5. ArrayList<Object> collection1=new ArrayList<>();
  6. collection1.add(1);
  7. collection1.add(1L);
  8. collection1.add("abc");
  9. int i=(Integer) collection1.get(0);
  10. System.out.println(collection1.get(0) instanceof Integer);
  11. Constructor<String> constructer1=String.class.getConstructor(String.class);
  12. String str=constructer1.newInstance("abc");
  13. System.out.println(str);
  14. }
  15. }
复制代码
2.内部原理

2.1.泛型是给编译器使用的,可以在限定集合中输入类型,让编译器挡住源程序中的非法输入,编译器编译生成的字节码会去掉方形的类型信息的,如下所示

  1. import java.util.ArrayList;
  2. public class Test {
  3. public static void main(String[] args) throws Exception {
  4. ArrayList<String> collection2 = new ArrayList<>();
  5. ArrayList<Integer> collection3 = new ArrayList<>();
  6. System.out.println(collection2.getClass() == collection3.getClass());
  7. }
  8. }
复制代码

也因此,如下代码并不是重载,是错误的,因为运行时会去泛型信息

  1. public static void applyVector(Vector<Date> v1){
  2. }
  3. public static void applyVector(Vector<String> v1){
  4. }
复制代码

就是说泛型只是给编译器看的,运行的时候就没有泛型信息了,也因此可以根据这种原理,以反射的原理得到集合再调用add方法,比如往上面collection3里添加String

  1. import java.util.ArrayList;
  2. public class Test {
  3. public static void main(String[] args) throws Exception {
  4. ArrayList<String> collection2 = new ArrayList<>();
  5. ArrayList<Integer> collection3 = new ArrayList<>();
  6. System.out.println(collection2.getClass() == collection3.getClass());
  7. // collection3.add("abc");
  8. // 报错
  9. collection3.getClass().getMethod("add", Object.class).invoke(collection3, 1);
  10. collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
  11. System.out.println(collection3);
  12. }
  13. }
复制代码

2.2 语法规定

ArrayList称为泛型类型,E称为类型变量或类型参数,<>做typeof

参数化类型不考虑类型参数的继承关系,下面两个都是错误的

  1. ArrayList<String> c=new ArrayList<Object>();
  2. ArrayList<Object> b=new ArrayList<String>();
复制代码

参数化和原始类型的兼容性,下面例子中C只能装string,而b可以加object,其实b那种写法和ArrayList b=new ArrayList()是一样的,因为泛型只是给编译器看的

  1. ArrayList<String> c=new ArrayList();
  2. c.add("asdf");
  3. System.out.println(c.get(0).getClass());
  4. ArrayList b=new ArrayList<String>();
  5. b.add(456);
  6. b.add("asdf");
  7. System.out.println(b.get(0).getClass());
  8. System.out.println(b.get(1).getClass());
复制代码

下面不报错的

  1. ArrayList b=new ArrayList<String>();
  2. ArrayList<Object> d=b;
复制代码

2.3 泛型通配符
比如现在要打印一个类型参数是任意类型的集合,如下写法就是不对的

  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. public class Test {
  4. public static void main(String[] args) throws Exception {
  5. ArrayList<String> collection2 = new ArrayList<>();
  6. ArrayList<Integer> collection3 = new ArrayList<>();
  7. System.out.println(collection3);
  8. printCollection(collection3);//编译器不通过,因为之前说过,泛型类型并不存在类型参数的继承关系
  9. }
  10. public static void printCollection(Collection<Object> collection){
  11. }
  12. }
复制代码

这就需要通配符了

  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. public class Test {
  4. public static void main(String[] args) throws Exception {
  5. ArrayList<String> collection2 = new ArrayList<>();
  6. ArrayList<Integer> collection3 = new ArrayList<>();
  7. System.out.println(collection3);
  8. printCollection(collection3);//编译器不通过,因为之前说过,泛型类型并不存在类型参数的继承关系
  9. }
  10. public static void printCollection(Collection<?> collection){
  11. // collection.add(123);
  12. // 会报错,因为使用了通配符,因此不能调用与类型参数相关的方法
  13. // 参数(int)不适用于Collection <capture#1-of?>类型的add(capture#1-of?)方法,
  14. collection.size();//这就没错,因为size方法与类型参数没有关系
  15. for (Object object : collection) {
  16. System.out.println(object);
  17. }
  18. }
  19. }
复制代码

使用?通配符可以引用各种参数类型,其主要作用是引用,而不是写入
通配符也有拓展功能

限定上边界
? extends Number要求传入的必须是Number的子类

限定下边界
? super Integer要求传入的必须是Integer的父类

3.自定义泛型

3.1 泛型方法

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. //结果就是二者的交集
  4. Number num=add(3,51.0);
  5. Integer inte=add(3,51);
  6. Object o=add(3,"123");
  7. swap(new String[]{"aaa","bbb","ccc"},1,2);
  8. // swap(new int[]{123,456,789},1,2);//泛型变量只能是引用对象,int[]已经是一个基本类型的数组,它并不能完成自动装箱
  9. }
  10. private static <T> T add(T x,T y){
  11. return null;
  12. }
  13. private static <T> void swap(T[] a,int i,int j){
  14. T temp=a[i];
  15. a[i]=a[j];
  16. a[j]=temp;
  17. }
  18. private static <T extends Exception> void sayHello() throws T{
  19. try{
  20. }catch(Exception e){//必须明确是哪个异常,不能catch T
  21. throw (T)e;
  22. }
  23. }
  24. }
复制代码

3.2 在类上定义泛型

就是为了保障类中的泛型能够统一,为此可以在类上定义泛型

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. GenericDao<String> dao=new GenericDao<>();
  4. dao.add("123");
  5. }
  6. }
  7. class GenericDao<T>{
  8. public void add(T x){
  9. }
  10. public T getByID(int id){
  11. return null;
  12. }
  13. public void delete(T obj){
  14. }
  15. }
复制代码

3.3 通过反射获得泛型的实际类型参数

之前说过,泛型是给编译器看的,因此假如有一个变量Vector v1,仅仅从v1这个变量,是没法知道这个Vector里的泛型到底是什么的,因此通过其他一种方法获得,

  1. import java.lang.reflect.Method;
  2. import java.lang.reflect.ParameterizedType;
  3. import java.lang.reflect.Type;
  4. import java.util.Date;
  5. import java.util.Vector;
  6. public class Test {
  7. public static void main(String[] args) throws Exception {
  8. Method applyMethod=Test.class.getMethod("applyVector", Vector.class);
  9. Type[] types=applyMethod.getGenericParameterTypes();
  10. /*
  11. * 按照声明顺序返回 Type 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的。如果底层方法不带参数,则返回长度为 0 的数组。
  12. * 如果形参类型是参数化类型,则为其返回的Type对象必须实际反映源代码中使用的实际类型参数。
  13. * 如果形参类型是类型变量或参数化类型,则创建它。否则将解析它。
  14. */
  15. ParameterizedType ptype=(ParameterizedType)types[0];
  16. System.out.println(ptype.getRawType());
  17. /*
  18. * 返回 Type 对象,表示声明此类型的类或接口。
  19. */
  20. System.out.println(ptype.getActualTypeArguments()[0]);
  21. /*
  22. * 返回表示此类型实际类型参数的 Type 对象的数组。
  23. */
  24. }
  25. public static void applyVector(Vector<Date> v1){
  26. }
  27. }
复制代码
五、类加载器 1.类加载器基本概念

要使用这个类,就要把.class文件加载进虚拟机,然后进行处理,就需要类加载器,Java虚拟机中可以安装多个类加载器,系统默认三个主要加载器,每个加载器都加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器本身也是一个Java类,因此也需要被加载,因此一个特殊的加载器,即BootStrap,它不是一个Java类
而Java虚拟机中所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象之前,需要指定一个父极类加载器对象

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. System.out.println(Test.class.getClassLoader().getClass());
  4. System.out.println(System.class.getClassLoader());
  5. // null,说明这是又bootstrap类加载器加载的
  6. ClassLoader loader=Test.class.getClassLoader();
  7. while(loader!=null){
  8. System.out.println(loader.getClass());
  9. loader=loader.getParent();
  10. }
  11. }
  12. }
复制代码
2.委托机制

(太困了扛不住了)

3.自定义类加载器

首先搞一个类的加密器,将类文件进行二进制简单加密,用生成的类文件覆盖掉原本的类文件后,再次运行程序,发现类加载错误

  1. import java.io.FileInputStream;
  2. import java.io.FileOutputStream;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.util.Date;
  6. public class MyClassLoader {
  7. public static void main(String[] args) throws Exception {
  8. String srcPath = "bin/zheteng/ClassLoaderAttachment.class";
  9. String destPath = "ClassLoaderAttachment.class";
  10. FileInputStream fis = new FileInputStream(srcPath);
  11. FileOutputStream fos = new FileOutputStream(destPath);
  12. cypher(fis,fos);
  13. fis.close();
  14. fos.close();
  15. System.out.println(new ClassLoaderAttachment().toString());
  16. }
  17. private static void cypher(InputStream ips, OutputStream ops) throws Exception {
  18. int b = -1;
  19. while ((b = ips.read()) != -1) {
  20. ops.write(b ^ 0xff);
  21. }
  22. }
  23. }
  24. class ClassLoaderAttachment extends Date {
  25. /**
  26. *
  27. */
  28. private static final long serialVersionUID = -1118939564631068343L;
  29. public String toString(){
  30. return "hello,world";
  31. }
  32. }
复制代码

下面再搞一个解密的类加载器

  1. import java.io.ByteArrayOutputStream;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.InputStream;
  5. import java.io.OutputStream;
  6. import java.util.Date;
  7. public class MyClassLoader extends ClassLoader {
  8. public static void main(String[] args) throws Exception {
  9. String srcPath = "bin/zheteng/ClassLoaderAttachment.class";
  10. String destPath = "ClassLoaderAttachment.class";
  11. FileInputStream fis = new FileInputStream(srcPath);
  12. FileOutputStream fos = new FileOutputStream(destPath);
  13. cypher(fis, fos);
  14. fis.close();
  15. fos.close();
  16. System.out.println(new ClassLoaderAttachment());
  17. Class d1 = new MyClassLoader().loadClass("ClassLoaderAttachment.class");
  18. Date d = (Date) d1.newInstance();
  19. System.out.println(d.toString());
  20. }
  21. private static void cypher(InputStream ips, OutputStream ops) throws Exception {
  22. int b = -1;
  23. while ((b = ips.read()) != -1) {
  24. ops.write(b ^ 0xff);
  25. }
  26. }
  27. @Override
  28. protected Class<?> findClass(String name) throws ClassNotFoundException {
  29. String classFileNmae = name;
  30. try {
  31. System.out.println(name);
  32. FileInputStream fis = new FileInputStream(classFileNmae);
  33. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  34. cypher(fis, bos);
  35. fis.close();
  36. byte[] bytes = bos.toByteArray();
  37. return defineClass(bytes, 0, bytes.length);
  38. } catch (Exception e) {
  39. // TODO Auto-generated catch block
  40. e.printStackTrace();
  41. }
  42. return super.findClass(name);
  43. }
  44. public MyClassLoader() {
  45. }
  46. }
复制代码

这次的attachment必须定义为public类否则上面的反射会异常访问权限报错

  1. import java.util.Date;
  2. public class ClassLoaderAttachment extends Date {
  3. /**
  4. *
  5. */
  6. private static final long serialVersionUID = -1118939564631068343L;
  7. public String toString(){
  8. return "hello,worldxx";
  9. }
  10. }
复制代码

其实我觉得这块讲的我没太听明白,以后看thingking in java的时候再补上吧

六、代理


太阳http代理AD
回复

使用道具 举报

发表于 2017-8-13 15:32:26
句号论坛
百度(常州)创新中心作为常州钟楼区政府、百度公司、江苏三艾网络科技有限公司三方联合打造的一个创新平台,以绝对的资源优势伫立在常州科技街。
办公就在家门口——区域
百度创新中心周边商务配套非常齐全,离规划中的地铁出口1000米,附近有宝龙广场,休闲、娱乐、餐饮非常方便。离常州大学白云校区、江苏城乡建设职业学院等也很近。阳光灿烂的日子里,不妨到青枫公园去划划船,彻底放飞自己的心情。







太阳http代理AD
回复 支持 反对

使用道具 举报

关闭

站长推荐上一条 /1 下一条