黑马程序员-Java高新技术笔记2

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

32_了解和入门注解的应用

了解注解及Java提供的几个基本注解

1、先通过@SuppressWarnings的应用让大家认识和了解一下注解:

通过System.runFinalizersOnExit(true);的编译警告引出@SuppressWarnings("deprecation")

2、@Deprecated

直接在刚才的类中增加一个方法,并加上@Deprecated标注,在另外一个类中调用这个方法。

3、@Override

public boolean equals(Reflect other)方法与HashSet结合讲解

常用几个注解

1.Deprecated          value = RUNTIME

用@Deprecated特点注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发生

2.Override             value = SOURCE

表示一个方法声明重写超类中的另个一方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误

3.SuppressWarnings  value = SOURCE

指示应该注释元素(以及包含在该注释元素中的所有程序元素)中取消现实制定的编译器警告。注意,在给定元素中取消现实的警告集市所有包含元素中取消显示的警告的超集。例如,如果注释一个雷来取消显示某个警告,同事注释一个方法来取消显示另一个警告,那么僵在此方法中同时取消显示着两个警告。

代码演示:

package com.itheima.day2;
 
public class AnnotationTest {
   @SuppressWarnings("deprecation")
   public static void main(String[] args) {
      // TODO Auto-generated methodstub
      System.runFinalizersOnExit(true);
      sayHello();
   }
   //1.标记某个方法过时;
   //2.子类覆盖父类
   //3.压缩警告
   @Deprecated //提示编译器说明下面这个方法过时,让调用这个方法的程序能够识别
   public static void sayHello(){
      System.out.println("hi,黑马程序员");
   }
}

总结:

1.注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。

2.看java.lang包,可看到JDK中提供的最基本的annotation。

 

33_注解的定义与反射调用

注解的应用

1、注解类

@interface A{}

2、应用了“注解类”的类

@A

Class B{}

3、对“应用了注解类的类”进行反射操作的类

class C{

B.class.isAnnotionPresent(A.class);

A a = B.class.getAnnotion(A.class);

}

注解就相当于一个你的源程序中药调用的一个类,要在源程序中应用某个注解,得先准备好了这个注解类。就像你要调用某个类,得先有开发好了这个类。

自定义注解

根据反射测试的问题,引出@Retention元注解的讲解,其三种取值:

java源文件:RetetionPolicy.SOURCE、

class文件:     RetetionPolicy.CLASS、

内存中的字节码:   RetetionPolicy.RUNTIME;

其中,注解的默认阶段处在class文件阶段

注解里面的枚举:Java.lang.annotation  Enum RetentionPolicy,其中该枚举有三个取值:CLASS:编译器将把注释记录在类文件中,但在运行时VM不需要保留注释。

RUNTIME:编译器将把注释记录在类文件中,在运行时VM将保留注释,因此可以反射性地读取。

SOURCE:编译器要丢弃的注释。

代码演示:

package com.itheima.day2;
@ItheimaAnnotation
public class AnnotationTest {
   @SuppressWarnings("deprecation")
   @ItheimaAnnotation
   public static void main(String[] args)throws Exception {
      // TODO Auto-generated methodstub
      System.runFinalizersOnExit(true);
      sayHello();
     
      if(AnnotationTest.class.isAnnotationPresent(ItheimaAnnotation.class)){
         ItheimaAnnotation annotation = (ItheimaAnnotation)AnnotationTest.class.getAnnotation(ItheimaAnnotation.class);
         System.out.println(annotation);
      }
   }
   //1.标记某个方法过时;
   //2.子类覆盖父类
   //3.压缩警告
   @Deprecated //提示编译器说明下面这个方法过时,让调用这个方法的程序能够识别
   public static void sayHello(){
      //System.out.println("hi,黑马程序员");
   }
}

package com.itheima.day2;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//元注解
@Retention(RetentionPolicy.RUNTIME)//这个注解表示让程序一直执行到运行期间
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItheimaAnnotation {
 
}


34_为注解添加各种属性

1、什么是注解的属性

一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则,就不是。如果还想区分出是传智播客哪个班的学生,这时候可以为胸牌在增加一个属性来进行区分。加了属性的标记效果为:@MyAnnotation(color="red")

2、定义基本类型的属性和应用属性:

在注解类中增加String color();

@MyAnnotation(color="red")

3、用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法

MyAnnotation a =(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);

System.out.println(a.color());

可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象

4、为属性指定缺省值:

String color()default "yellow";

5、value属性:

String value()default "zxx";

如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略value=部分,例如:@MyAnnotation("lhm")。

 

部分代码演示:

package com.itheima.day2;
@ItheimaAnnotation(annotationAttr=@MetaAnnotation("flx"), color="red",value="abc", arrayAttr={1,2,3} )
public class AnnotationTest {
   @SuppressWarnings("deprecation")
   @ItheimaAnnotation("xyz")
   public static void main(String[] args)throws Exception {
      // TODO Auto-generated methodstub
      System.runFinalizersOnExit(true);
      sayHello();
     
      if(AnnotationTest.class.isAnnotationPresent(ItheimaAnnotation.class)){
         ItheimaAnnotation annotation = (ItheimaAnnotation)AnnotationTest.class.getAnnotation(ItheimaAnnotation.class);
        
         System.out.println(annotation.lamp().nextLamp().toString());
         System.out.println(annotation.annotationAttr().value());
      }
   }
}


35_入门泛型的基本应用

代码演示:

package com.itheima.day2;
 
import java.lang.reflect.Constructor;
import java.util.ArrayList;
 
public class GenericTest {
 
   public static void main(String[] args)throws Exception{
      // TODO Auto-generated methodstub
      /*ArrayList collection = new ArrayList();
      collection.add(1);
      collection.add(1L);
      collection.add("abc");
      int i =(Integer)collection.get(1);*/
     
      ArrayList<String>al = new ArrayList<String>();
      al.add("abc");
      al.add("bbb");
      al.add("acd");
      String element =al.get(2);
      System.out.println(element);
     
      Constructor<String>constructor1 = String.class.getConstructor(StringBuffer.class);//这里的StringBuffer是选择哪个构造方法
      //将Constructor添加String类型的泛型后,后面的返回值前就不再需要将其强制转换成String类型了
      String str2 =constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));     
      System.out.println(str2.charAt(2));
   }
 
}

小结:泛型是JDK1.5的所有新特性中最难深入掌握的部分,不过,我们在实际应用中不需要掌握的那么深入,掌握泛型中一些最基本的内容就差不多了。没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全,并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,这样更方便。

 

 

36_泛型的内部原理及更深应用

泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。

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称为原始类型

2、参数化类型与原始类型的兼容性:

1.参数化类型可以引用一个原始类型的对象,编译报告警告,例如,
Collection<String> c = new Vector();//可不可以,不就是编译器一句话的事吗?

2.原始类型可以引用一个参数化类型的对象,编译报告警告,例如,
Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去

3、参数化类型不考虑类型参数的继承关系:

Vector<String> v = new Vector<Object>(); //错误!

//不写<Object>没错,写了就是明知故犯

Vector<Object> v = new Vector<String>(); // 错误!


37_泛型的通配符扩展应用

1、使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

2、限定通配符的上边界:

正确:Vector<? extends Number> x = new Vector<Integer>();

错误:Vector<? extends Number> x = new Vector<String>();

3、限定通配符的下边界:

正确:Vector<? super Integer> x = new Vector<Number>();

错误:Vector<? super Integer> x = new Vector<Byte>();

小结:

限定通配符总是包括自己。

?只能用作引用,不能用它去给其他变量赋值


38_泛型集合的综合应用案例

代码演示:

HashMap<String,Integer> maps = new HashMap<String,Integer>();
      maps.put("zxx", 28);
      maps.put("lhm", 35);
      maps.put("flx", 33);
     
      Set<Map.Entry<String,Integer>>entrySet = maps.entrySet();
      for(Map.Entry<String, Integer> entry :entrySet){
         System.out.println(entry.getKey() +":" + entry.getValue());
      }


39_自定义泛型方法及其应用

1、自定义泛型模板中,其函数结构相似,但类型不同,这里可以使用一个通用的方法,它可以适用于各种类型,例如:

template<classT>

Tadd(T x,T y){

return(T)(x+y);

}

其中,代码里面的T代表一种任意数据类型

 

2、Java中的泛型类型(或者泛型)类似于C++中的模板。但是这种相似性仅限于表面,Java语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型推断,然后生成普通的非凡行的字节码,这种实现技术成为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后再生成字节码之前将其清除)。这是因为扩展虚拟机指令集来支持泛型呗认为是无法接受的,这会为Java厂商升级其JVM造成难以逾越的障碍。所以,Java的泛型采用了可以完全在编译器中实现的擦除方法。

 

代码演示:

classGenericTest{
public static voidmain(String[] args){
add(3,5);
      Number x1 = add(3.5,3);
      Object x2 = add(3,"abc");//类似于数学中的“最大公约数”,找到其共同的对应类型即可
     
      swap(new String[]{"abc","xyz","itheima"},1,2);
      swap(new Integer/*int*/ []{1,2,3,4,5},3,4);//只有引用类型才能作为泛型方法的实际参数 
      //泛型的实际类型,只能是对象的引用类型,不能使基本数据类型,因为只有引用类型才能作为泛型方法的实际参数
   }
  
   public static <T> void swap(T[] a,int i,int j){
      //由于这里接收的数组类型可能是任意类型,因此将其修改成T类型,然后在返回值前面添加泛型<T>,表示接收的类型
      T tmp = a[i];
      a[i] = a[j];
      a[j] = tmp;
   }
  
   public static <T> T add(T x,T y){//在返回值之前用一对<>表示其类型
      return null;
   }
}


3、泛型中是如何处理异常的

publicstatic <T extends Exception> sayHello() throws T{

try{}

catch(Exception e){

throw (T)e;

}

}

其中:T必定是Exception的子类,然后在处理catch的时候,还是用Exception e而不能用T代替,最后将抛出的e降至转换成(T)这种类型即可;


40_自定义泛型方法的练习与类型推断总结

泛型方法的练习题

1、编写一个泛型方法,自动将Object类型的对象转换成其他类型。

classGenericTest{

public static voidmain(String[] args){

Object obj = “abc”;

String a =autoConvert(obj);

}

public static <T> TautoConvert(Object obj){

return (T)obj;

}

}

 

2、根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:

1.当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:

        swap(new String[3],3,4)       static <E> voidswap(E[] a, 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 =(3,3.5f)    static <T> T add(T a, T b)

 

5.参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题:

       copy(newInteger[5],new String[5])  static <T> void copy(T[] a,T[]  b);

       copy(newVector<String>(), new Integer[5])  static <T> void copy(Collection<T> a , T[] b);

 

 

41_自定义泛型类的应用

1、如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如下:

       publicclass GenericDao<T> {

              privateT field1;

              publicvoid save(T obj){}

              publicT getById(int id){}

       }

2、类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:

GenericDao<String> dao = null;

new genericDao<String>();

 

注意:

1.在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。

2.当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数。

 

代码演示:

 

GenericDao.java源码:

package com.itheima.day2;
 
import java.util.Set;
 
//dao--> Data Access Object:数据访问对象-->crud:create增、read检索、update改、delete删
public class GenericDao<T> {
   //为了让程序里的T即返回值类型是统一的,如果只在方法上定义其返回值类型,最后得到的数据可能不是统一类型,
   //因此这里可以将T返回值定义在类上,因此就能统一返回值类型,保证了数据的安全性
   public  void add(T x){   }
   public T findById(int id){
      return null;
   }
   public void delete(T obj){ 
   }
   public void delete(int id){
   }
   public void update(T obj){ 
   }
   public TfindByUserName(String name){
      return null;
   }
   public Set<T> findByConditions(String where){
      return null;
   }
}

//自定义泛型类的应用

      GenericDao<ReflectPoint>dao = newGenericDao<ReflectPoint>();

      dao.add(new ReflectPoint(3,3));

      //String s = dao.findById(1);

 

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

代码演示:

class GenericTest{
public static void main(String[] args){
      //以泛型的方式得到实际类型的参数
      //Vector<Data> v1 = new Vector<Date>();
      Method applyMethod =GenericTest.class.getMethod("applyVector", Vector.class);
      Type[] types =applyMethod.getGenericParameterTypes();//获取参数值类型
      ParameterizedType pType= (ParameterizedType)types[0];
      System.out.println(pType.getRawType());
      System.out.println(pType.getActualTypeArguments());
   }
  
   public static void applyVector(Vector<Date> v1){
     
   }


43_类加载器及其委托机制的深入分析

1、Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader

2、类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。

3、Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。


 代码演示:

package com.itheima.day2;
 
public class ClassLoaderTest {
 
   public static void main(String[] args) {
      // TODO Auto-generated methodstub
     Object obj  = ClassLoaderTest.class.getClassLoader().getClass().getName();
      System.out.println(obj);
      Object obj1 = System.class.getClassLoader();
      System.out.println(obj1);
      //Java类加载器中有一个特殊的类加载器:BootStrap
     
      ClassLoader loader =ClassLoaderTest.class.getClassLoader();
      while(loader !=null){
         System.out.println(loader.getClass().getName());//获取其类加载器的名称
         loader =loader.getParent();//获取其类加载器的父类名称
      }
      System.out.println(loader);
     
   }
 
}


4、类加载器的委托机制

1.当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

a.首先当前线程的类加载器去加载线程中的第一个类。

b.如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。

c.还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

 

2.每个类加载器加载类时,又先委托给其上级类加载器。

a.当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

b.对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。

 

 

44_自定义类加载器的编写原理分析

1、自定义的类加载器的必须继承ClassLoader

loadClass方法与findClass方法

defineClass方法

2、编程步骤:

1.编写一个对文件内容进行简单加密的程序。

2.编写了一个自己的类装载器,可实现对加密过的类进行装载和解密。

3.编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。

3、实验步骤:

1.对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如: javaMyClassLoader MyTest.class F:\itcast

2.运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast

3.用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败。

4.删除CLASSPATH环境下的类文件,再执行上一步操作就没问题了。

 

4、findClass

protected Class<?> findClass(Stringname) throws ClassNotFoundException

使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载雷。在通过父类加载器检查所请求的类后,此方法将被loadClass方法调用,默认实现抛出一个ClassNotFoundException;

代码演示:

class NetworkClassLoader extends ClassLoader{
String host;
int port;
 
public Class findClass(String name){
byte[] bu = loadClassData(name);
return defineClass(name,b,0,b.length);
}
private byte[] loadClassData(String name){
//load the class data from the connection
}
}


45_编写对class文件进行加密的工具类

代码演示:

//编写一个继承Date的类,并覆盖toString方法

package com.itheima.day2;
import java.util.Date;
public class ClassLoaderAttachmentextends Date {
   public String toString(){
      return "hello,itheima";
   }
}

//编写一个字节码加密类,对相应文件进行加密

package com.itheima.day2;
 
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
 
public class MyClassLoader {
   //编写对class文件进行加密的工具类
   public static void main(String[] args)throws Exception{
      // TODO Auto-generated methodstub
      String srcPath =args[0];
      String destDir = args[1];
      FileInputStream fis = new FileInputStream(srcPath);
      String destFileName =srcPath.substring(srcPath.lastIndexOf('\\')+1);
      String destPath = destDir +"\\"+ destFileName;
      FileOutputStream fos = new FileOutputStream(destPath);
      cypher(fis,fos);
      fis.close();
      fos.close();
 
   }
   private static void cypher(InputStream ips,OutputStream ops)throws Exception{
      int b = -1;
      while((b=ips.read())!=-1){
         ops.write(b ^ 0xff);
      }
   }
 
}

小结:有包名的类不能调用无包名的类

46_编写和测试自己编写的解密类加载器

代码演示:

MyClassLoader1.java文件

package com.itheima.day2;
 
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
 
public class MyClassLoader1 extends ClassLoader{
 
   public static void main(String[] args)throws Exception {
      // TODO Auto-generated methodstub
      String srcPath = args[0];
      String destDir = args[1];
      FileInputStream fis = new FileInputStream(srcPath);
      //目标原名称
      String destFileName =srcPath.substring(srcPath.lastIndexOf('\\')+1);
      //目标原路径
      String destPath =destDir + "\\" + destFileName;
      FileOutputStream fos = new FileOutputStream(destPath);
     
      cypher(fis,fos);
      fis.close();
      fos.close();
 
   }
   public static void cypher(InputStream ips, OutputStream ops)throws Exception{
      int b = -1;
      while((b=ips.read())!=-1){
         ops.write(b ^ 0xff);
      }
   }
   //产生一个classDir成员变量
   private String classDir;
  
   @Override
   protected Class<?> findClass(String name)throws ClassNotFoundException {
      // TODO Auto-generated methodstub
      String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) +".class";
      try{
         //由于这里是子类抛出异常,只能使用try,catch处理,因为其子类要抛的异常比父类范围大
         FileInputStream fis= newFileInputStream(classFileName);
         //定义一个字节输入流
         ByteArrayOutputStreambos = new ByteArrayOutputStream();
         cypher(fis,bos);
         fis.close();
         byte[] bytes = bos.toByteArray();
         return defineClass(bytes,0,bytes.length);
        
      }catch(Exception e){
         e.printStackTrace();
      }
      return super.findClass(name);
   }
  
   //创建一个不带参数的MyClassLoader
   public MyClassLoader1(){
     
   }
  
   //创建一个带参数的MyClassLoader
   public MyClassLoader1(String classDir){
      this.classDir = classDir;
   }
}

ClassLoaderTest.java文件

package com.itheima.day2;
 
import java.util.Date;
 
public class ClassLoaderTest {
 
   public static void main(String[] args)throws Exception{
      // TODO Auto-generated methodstub
     Object obj  = ClassLoaderTest.class.getClassLoader().getClass().getName();
      System.out.println(obj);
      Object obj1 = System.class.getClassLoader();
      System.out.println(obj1);
      //Java类加载器中有一个特殊的类加载器:BootStrap
     
      ClassLoader loader =ClassLoaderTest.class.getClassLoader();
      while(loader !=null){
         System.out.println(loader.getClass().getName());//获取其类加载器的名称
         loader =loader.getParent();//获取其类加载器的父类名称
      }
      System.out.println(loader);
     
      //System.out.println(new ClassLoaderAttachment().toString());
     
      Class clazz = new MyClassLoader1("itheimalib").loadClass("com.itheima.day2.ClassLoaderAttachment");
      //由于这里是自定义的ClassLoaderAttachment类,因此编译器是无法识别的,所以得将其强制转换
      //ClassLoaderAttachment d1 = (ClassLoaderAttachment)clazz.newInstance();
      //由于之前定义的是Date类,因此这里可以直接将其转成Date的类
      Date d1 =(Date)clazz.newInstance();
      System.out.println(d1);
     
   }
 
}

ClassLoaderAttachment.java文件

package com.itheima.day2;
 
import java.util.Date;
 
public class ClassLoaderAttachmentextends Date {
   public StringtoString(){
      return"hello,itheima";
   }
}


---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值