• Java小结


    1. 反射

    java数据类型分为原始类型和引用类型。对于每种类型的对象java虚拟机会实例化不可变的java.lang.Class对象,它提供了在运行时检查对象属性的方法,这些属性包括它的成员和类型信息。

    注:Class是泛型类,可以使用@SuppressWarnings("unchecked")忽略泛型或者使用Class<?>类型,?表示任意类型。

    • 获取class对象的五种方法

      • Object.getClass():如果一个类的对象可用,则最简单的获的Class的方法是使用Object.getClass()(只对引用类型有用);
      • .class:若果类型可用但没有对象,可以在类型后加上".class"来获的Class对象;
      • Class.forName():如果知道类的全名,可使用静态方法Class.forName来获的Class对象,但它不能用在原始类型上,抛出ClassNotFoundException异常;
      • 包装类的Type域:每个原始类型和void都有包装类,利用其Type域就可以获的Class对象(注:Double Integer分别是double以及int的包装类);
      • 以Class返回值得方法:参考反射API。
    • getName的返回值

    对不同类型的对象或类,class对象的名称是不同的,从这个名称就可以判断原来类型的,所有数组对象都有"["。具体返回值为:

    如果此类对象表示的是非数组类型的引用,则返回该类的二进制名称(如java.lang.Class);

    如果此类对象表示一个基本类型(如int,long)或void,则返回的名字是一个基本类型或void所对应的java语言关键字相同的字符串;

    如果此类对象表示一个数组,名字的内部形式为:表示该数组嵌套深度的一个或多个"["字符加元素类型名,元素类型名的编码为:

    元素类型

    编码

    元素类型

    编码

    元素类型

    编码

    boolen

    Z

    int

    I

    char

    C

    byte

    B

    float

    F

    long

    J

    double

    D

    short

    S

    class or interface

    LclassName

       

       

    //1. 获得引用类型名称

    String dateName = new Date().getClass().getName();// 对象获的Clas对象

    String dateClassName = Date.class.getName();//类获的Class对象

    String dateClassForName = Class.forName("java.util.Date").getName();

    --他们都返回类的二进制名称:java.util.Date

    //2. 获得原始类型名称

    String byteName = int.class.getName();// 获得原始类型名称

    --返回值为int

    //3. 引用类型数组

    String oneDimensionArray = new Date[4].getClass().getName();

    --一维:[Ljava.util.Date

    String twoDimensionArray = new int[4][4].getClass().getName();

    --二维:[[I

    1. 查看类声明

    通常类的声明包括常见修饰符(public,protected,private,abstract,static,final) 类的名称、类的泛型参数、类的继承类(实现的接口)、类的注解等信息。

    Class类的实例表示正在运行的java应用程序中的类和接口。枚举是一个类,注释是一个接口,每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。

    Class类常用方法:

    注:Java语言预定义的注解只有@Deprecated可以在运行时获得。

       

    Class<?> clazz = Class.forName("java.util.ArrayList");// 获得ArrayList类对象

    // 1. 输出类的泛型参数

    TypeVariable<?>[] typeVariables = clazz.getTypeParameters();

    // 2. 输出类所实现的所有接口

    Type[] interfaces = clazz.getGenericInterfaces();

    //3. 输出类的直接继承类,如果是继承自Object则返回空

    Type superClass = clazz.getGenericSuperclass();

    //4. 输出类的所有注释信息,有些注释信息是不能用反射获得的

    Annotation[] annotations = clazz.getAnnotations();

    一、Type类型

    Type是Java编程语言中所有类型的普通的父接口。这些类型包括原生类型(raw types),参数化类型(parameterized types),数组类型(array types),类型变量(type variables)和 原始类型(primitive types)。我们一般不直接操作Type类型,但了解一下Type类型的层次结构还是有必要的。

    1、Type层次结构

       

    2、Class,Method和Field的继承体系

       

    在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息保存着每个对象所属的类足迹。虚拟机利用运行时信息选择相应的方法执行。然而,可以通过专门的Java类访问这些信息。保存这些信息的类称为Class,泛型形式为Class。Class是反射机制的基础,反射API通过操作Class来获取其完整结构。

    1. 查看类成员

    类的成员包括成员变量、方法、构造器以及内部类等,常用方法如下:

    另:getDeclaredClasses() 返回该对象的内部类

    classObject.getDeclareField("域的字符串形式")

    getDeclareField与getField区别:前者获取所有成员变量,后者只获取public成员变量。

    Class<?> clazz = Class.forName("java.util.ArrayList");// 获得ArrayList类对象

    //1. 获得该类对象的所有构造方法

    Constructor[] constructors = clazz.getConstructors();

    //2. 获得该类对象的所有非继承域

    Field[] fields = clazz.getDeclaredFields();

    //3. 获得该类对象的所有非继承方法

    Method[] methods =clazz.getDeclaredMethods();

    1. 按继承层次对类排序

    Class类中的isAssignableFrom方法用来判断当前Class对象所表示的类与给定的Class对象所表示的类之间的关系,如果相同或者是其父类,则返回true,如clazz1.isAssignableFrom(clazz2) 若clazz1是否是clazz2父类

    排序:

    TreeSet<E>是基于TreeMap的NavigableSet实现的,它使用元素的自然顺序或创建TreeSet<E>对象时提供的Comparator对元素进行排序。

    //重写Comparator接口指定其泛型类型为Class<?>

    public class ClassComparator implements Comparator<Class<?>> {

    @Override

    // 通过实现Comparator接口来实现比较功能

    public int compare(Class<?> clazz1, Class<?> clazz2) {

    if (clazz1.equals(clazz2)) {// 如果两个类对象相同则返回0

    return 0;

    }

    if (clazz1.isAssignableFrom(clazz2)) {

    return -1; // 如果clazz1所表示的类是clazz2所表示的类的父类则返回-1

    }

    if (clazz2.isAssignableFrom(clazz1)) {

    return 1; // 如果clazz1所表示的类是clazz2所表示的类的子类则返回1

    }

    throw new IllegalArgumentException("两个类之间没有关系");// 其他情况抛出异常

    }

    }

    //创建TreeSet对象时指定排序方式,以及确定泛型为Class<?>

    TreeSet<Class<?>> treeSet = new TreeSet<Class<?>>(new ClassComparator())

    treeSet.add(JPanel.class);// 向树集中添加JPanel.class

    System.out.println(treeSet.last());// 获得树集的最后一个元素

    1. 动态设置类的私有域

    Field类提供有关类或接口的的单个字段信息,以及对他的动态访问权限,反射的字段可能是一个类(静态)字段或实例字段。Field类常用方法有:

    注:对于私有域,首先要用setAccessible()将其可见性设置为true才能设置新值。

    在set(Object obj,Object value)函数中,obj为字段所在的对象,若为静态字段,则obj为null,value为设置的值。

       

    Student student =new Student(); //创建实例对象

    Class<?> stuClass = student.getClass();//获取反射对象

    Field accountField = stuClass.getDeclaredField("account");//获取指定字段的值

    accountField.setAccessible(true);//字段的可见性设为true

    accountField.set(student, 200);//设置值为200

    accountField.setDouble(student, 300);

    System.out.println(student.getAccount());

    1. 动态调用类中的方法

    Java中调用类的方法有两种方式:对于静态方法,可以直接使用类名调用,对于非静态方法,必须使用类的对象调用。

    Method类提供类或接口上单独某个方法(以及如何方法该方法)的信息。它通过public Object invoke(Object obj, Object …args)调用方法,obj为方法所在的对象,静态方法为null,…args为参数,返回值为Object类型。

    1.获取指定名称的无参数方法

    Method showMethod = stuClass.getDeclaredMethod("show");

    2.调用指定对象的无参方法

    showMethod.invoke(student);

    3.获取指定名称的方法,后面的参数是参数的类型

    Method showInfo = stuClass.getDeclaredMethod ("showInfo",String.class,int.class);

    4.调用指定参数的方法,后面的参数是参数的值,要与参数类型相对应

    String rString=(String)showInfo.invoke(student,"DSL",20);

    1. 动态实例化对象

    java通常使用构造方法来创建对象,构造方法分为有参数和无参数两种,如果类中没有定义构造方法,编译器会自动添加一个无参数的构造方法。Constructor类提供类的单个构造方法的信息以及对它访问权限。它允许在将实参与带有底层构造方法的形参的newInstrance()匹配时进行转换。

    public T newInstance(Object …args)

    //获取类的无参数构造器属性

    Constructor<Student> constructor = Student.class.getDeclaredConstructor();

    //调用无参数的构造器创建对象

    Student studentCreate = constructor.newInstance();

    //获取类的有参数构造器属性

    Constructor<Student> constructorArgs = Student.class.getDeclaredConstructor(String.class,int.class,double.class);

    //传入参数创建对象

    Student studentCreateArgs = constructorArgs.newInstance("DSL",28,7000);

    1. 创建可变长度数组

    ArrayList可以动态添加和删除数组。

    Array提供了动态创建和访问java数组的方法,允许在执行get或set操作期间进行扩展转换,它也提供获取/删除指定位置元素的方法。

    对于Class类实例,classObject.isArray()判断classObject是否是数组类型。

    public static Object increaseArray(Object array) {

    Class<?> clazz = array.getClass();// 获得代表数组的Class对象

    if (clazz.isArray()) {// 判断其对应的类型是否是数组

    // 获得数组元素的类型

    Class<?> componentType = clazz.getComponentType();

    int length = Array.getLength(array);// 获得输入的数组的长度

    // 新建数组指定数组元素类型以及长度,创建新的数组对象

    Object newArray = Array.newInstance(componentType, length + 5);

    System.arraycopy(array, 0, newArray, 0, length);// 复制原来数组中的所有数据

    return newArray;// 返回新建数组

    }

    return null;// 如果输入的不是数组就返回空

    }

    1. 反射与动态代理

    使用代理可以在运行时创建一个实现了一组给定接口的新类,这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。

    Invocationhandler接口是代理实例的调用处理程序实现的接口,对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的invoke()方法,该方法声明如下:

    Object invoke(Object proxy,Method method,Object[] args)

    method:所代理的代理类中的方法,由代理类调用其方法时传入

    args:代理类方法的参数,由代理类代用其方法时传入

    Poxy接口提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。本实例使用该接口中定义的newProxyInstance()方法获的一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

    public static Object newProxyInstance(ClassLoader loader,Class<?> interfaces, InvocationHhandler)

    loader:定义代理类的类加载器;

    interfances:一个Class对象数组,代理类要实现的接口列表;

    InvocationHander:指派方法调用的调用处理程序。

    分别通过接口实现以及代理实现接口Seller:

    public interface Seller {

    void sell();// 简单的测试方法

    }

    普通方法:

    public class HouseSeller implements Seller {

    // 实现接口的方法,用输出来区别该类

    public void sell() {

    System.out.println("销售人员在卖房子"); }

    }

       

    //在main方法中调用,创建对象,在调用方法

    Seller seller = new HouseSeller();

    eller.sell();// 普通方式调用sell()方法

       

    通过代理实现接口

    //1.首先实现InvocationHandler接口,并重写invoke方法,用Proxy创建的代理类实例无论调用什么方法都是在调用Agency中的 invoke()方法

    public class Agency implements InvocationHandler {

    private Object target;//在构造函数中赋值

    /// 用来处理代理类,正真实现代理类的方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("代理人员在卖房子");

    //在此处正真调用target中的method方法,要求target实现Seller接口

    method.invoke(target,args);

    return null;

    }

    }

       

    //在main函数中

    // 获得接口Seller类的类加载器

    ClassLoader loader = Seller.class.getClassLoader();

    //生成代理类实例

    seller = (Seller) Proxy.newProxyInstance(loader, new Class[] { Seller.class }, new Agency());

    seller.sell();// 代理方式调用sell()方法,其实在调用Agency中的invoke方法

    seller.sell(100,"DSL")//有参数的方法

    1. 异常

      1. 异常分类

    所有异常都是由Throwable继承而来,在下一层分解为两个分支:Error和Exception。

    • Error类层次结构描述了java运行时系统内部错误和资源耗尽错误(无力解决)。
    • Exception类层次分为两个分支,如下:
    • 程序自身错误导致的异常属于RuntimeException,包括错误的类型转换、数组访问越界、访问空指针、除数为零等。
    • 程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常,如试图在文件尾部后面读取数据、试图打开一个不存在的文件等。

    未检查异常(unchecked):派生于Error类或RuntimeException类的所有异常称;

    已检查(checked):所有其他的异常。

    1. 声明已检查异常

    方法上抛出异常:一个方法必须声明所有可能抛出的已检查异常,这样可以从首部反映出这个方法可能抛出哪类已检查异常(如果暂时不处理这些异常)。当重写继承的方法时,抛出的异常不能比超类的范围大,或者不抛出异常。

    public Image loadImage(String s) throws FileNotFoundException,EOFException

    {

    }

    方法中抛出异常:对于系统预定义的异常,一般至少有两个构造方法,即空参数构造方法和字符串参数构造方法。使用字符串参数构造方法可以让用户为该构造方法增加提示信息。

    public Image loadImage(String s)

    {

        throw FileNotFoundException("Hello world")

    }

    1. 自定义异常类

    自定义异常类派生于Exception或它的子类,包含两个构造函数,可以用getMessage()获取传入的信息:

    class FileFormatException extends IOException

    {

        pubic FileFormatException()

        {

        }

        public FileFormatException(String str)

        {

            super(str);

        }

    }

    1. 捕获异常

    如果某个异常发生的时候没有在任何地方进行捕获,那程序就会终止执行,并在控制台上打印出异常信息,其中包括异常的类型和堆栈信息。如果调用了一个抛出已检查异常的方法,就必须对它进行处理,或者通过throws/throw将它继续进行传递。

    通过try/catch/finally语句块捕获异常。

    1. 再次抛出异常与异常链

    在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型,如将SQLException异常转为ServletException异常:

    try{…}

    catch(SQLException e)

    {

        throw new SerleException("database error:"+e.getMesssage());//再次抛出异常

    }

    将原始异常设置为新异常的"原因":

    new SerleException("database error").initCause(e).

    重新获取原始异常:Throwable e = se.getCause();

    1. finally子句

    不管是否有异常被捕获,finally子句中的代码被执行。

    问题:当finally与try同时发生异常时,finally中抛出的异常会覆盖try中抛出的异常。

    try{…}

    finally

    {

        in.close();

    }

    finally子句包含return语句时。假设利用return语句从try语句块中退出。在方法返回前,finally子句的内容将被执行,如果finally子句中也有一个return语句,这个返回值将会覆盖原始的返回值,如下例,返回值为8

    try{

        return 4;

    }

    finally

    {

        return 8;

    }

    1. 带资源的try语句

    Java SE 7的AutoCloseable接口有一个方法:

    void close() throws Exception;

    假设资源属于一个实现了AutoCloseable接口的类,可以用带资源的try语句(try-with-resources),它会自动关闭资源:

    try(Scanner in = newScanner(new FileInputStream("/usr/share.dict"),

    PrintWriter out = new PrintWriter("out.txt"))

    {

       

    }

    不论这个块如何退出,in和out都会关闭。带资源的try语句可以使原来try中的异常重新抛出,而close方法抛出的异常会"被抑制"。

    1. 分析堆栈跟踪元素

    堆栈跟踪(stack trace)是一个调用过程的列表,它包含了程序执行过程中方法调用的特定位置。

    Throwable类的printStackTrace()方法访问堆栈跟踪的文本信息,显示异常类型、异常信息、异常发生位置;

    getMessage ()获取传入异常类的异常信息;

    StackTraceElemen类含有能够获得文件名、类名、方法名和当前执行的代码行号;

    Throwable t = new Throwable();

    StackTraceElement[] frames = t.getStackTrace();

    for (StackTraceElement f : frames)

    System.out.println(f);

    静态的Thread.getAllStackTrace方法,它可以产生所有线程的堆栈跟踪。

    从各处转载java文件
  • 相关阅读:
    PHP开发经常遇到的几个错误
    PHP的Trait
    PHP反射API
    php split 和 explode 的区别
    php判断检测一个数组里有没有重复的值
    PHP serialize 和 JSON 解析与区别
    php 单文件上传
    php 数组 类对象 值传递 引用传递 区别
    六. 网络编程(解决黏包TCP)
    五. 网络编程(UDP 不黏包)
  • 原文地址:https://www.cnblogs.com/ncscherb/p/5515972.html
Copyright © 2020-2023  润新知