• 第5章 继承与反射


    第5章 继承

    5.1 一般性总结

    1. 子类不可以访问父类的私有域
    2. 使用super调用父类构造器的语句必须是子类构造器语句的第一条
    3. final类和final方法:
    • final方法不可以被子类覆盖,但是可以被继承,只是不能覆盖而已
    • final类不可以被继承,它的所有方法都是final方法
    1. xx instanceof yy 用来检查xx对象是否可以强转为yy
    2. 抽象类相关:
    • 只要包含一个抽象方法,就必须将该类声明为abstract类
    • 也可以将一个不含抽象方法的类定义为抽象类,这样该类就不能实例化了
    • 实际开发中,很少用到抽象类,实现抽象类的具体方法用extends
    • 抽象类可以有构造函数,但是不能被实例化,对于继承它的子类,可以调用super()来完成构造函数的调用。
    1. Java中数组也是一种对象,都扩展了Object类
    2. Object.equals(a,b)和a.equals(b)的对比:
    • a.equals(b):当a对象为null时,该方法会报错
    • Objects.equals(a,b):a和b都为null,返回true。其中一个为null,返回false,否则就调用a.equals(b)
    1. 默认的equals()返回对象的地址,而默认的hashCode()得到对象的存储地址,这两个方法必须一致

    5.2 反射

    1. 获得Class对象的3种方法:
      • 利用对象的getClass()
      • 利用Class.forName(带包名的类名),用这个方法必须进行异常处理
      • Java类型.class,例如User.class
    2. class对象的newInstance()方法只能调用空参构造,没有的话会有异常
    3. Class对象的各种get方法:
      • getFields、getMethods、getConstructors:分别返回类提供的public域、方法和构造器,其中包括超类的公有成员
      • getDeclareFields、getDeclareMethods、getDeclareConstructors:分别返回类提供的全部域、方法和构造器,但是不包括超类的成员
    4. Modifier类的各种静态方法负责接管修饰符的String化,还有判断一个modifiers是不是private、public等等,典型的调用是:Modifier.toString(对象.getModifiers())
    5. 如果要利用反射机制访问私有域、方法,可以调用Field、Method、Constructor对象的.setAccessible(true)来实现,这样调用Field对象f.get(0bj)就可以访问私有域了。
    6. 通用toString方法的编写:
    public class ObjectAnalyzer {
        private List<Object> container = new ArrayList<>();
    
        private String toStringCore(Object obj){
            // 如果对象为空,直接返回null
            if(obj == null) return  "null";
    
            // 如果该对象的地址已经打印过了,就打印...
            if(container.contains(obj)) return "...";
    
            // 新对象,加入存在列表中
            container.add(obj);
    
            // 获取该对象的class对象
            Class clazz = obj.getClass();
    
            // 如果该类型是一个String,直接返回即可
            if(clazz == String.class) return (String) obj;
    
            // 如果对象是一个数组,注意不是集合对象
            if(clazz.isArray()){
                // 拿到数组的长度
                int length = Array.getLength(obj);
                // 拿到数组的元素类型
                Class componentType = clazz.getComponentType();
                String s = componentType.getName() + "[]{";
                // String s = componentType.toString() + "[]{";
                for (int i = 0; i < length; i++) {
                    Object component = Array.get(obj, i);
                    if(i > 0) s += ", ";
                    if(componentType.isPrimitive()) s += component;
                    else s += toStringCore(component);
                }
                return s + "}";
            }
    
            String r = clazz.getName();
            r += "[";
            do{
    
                // 拿到所有的域
                Field[] fields = clazz.getDeclaredFields();
                // 一定记得设置私有域可访问
                AccessibleObject.setAccessible(fields,true);
    
                // 遍历所有的域
                for (Field field : fields) {
                    // 如果这个域是个static域,它不隶属于对象,不打印
                    if(!Modifier.isStatic(field.getModifiers())){
                        if(!r.endsWith("[")) r += ", ";
                        // 拿到域的名字
                        String name = field.getName();
                        r += name + "=";
                        try {
                            // 拿到该域的值
                            Object val = field.get(obj);
                            // 拿到该域的装的东西的class对象
                            Class type = field.getType();
    
                            // 判断是不是基本类型
                            if(type.isPrimitive()) r += val;
                            else r += toStringCore(val);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
                clazz = clazz.getSuperclass();
            }while (clazz != null);
            r += "]";
            return r;
        }
    
        public String toString(Object object){
            String s = toStringCore(object);
            container.clear();
            return s;
        }
    
    }
    
    1. 编写扩展任意类型数组的方法(Array.copyOf只能扩展对象数组,基本类型的不行)
    public static Object goodCopyOf(Object obj, int newLength){
    	Class c = obj.getClass();
    	// 如果不是数组,就滚蛋
    	if(!c.isArray()) return null;
    	// 拿长度
    	int length = Array.getLength(obj);
    	// 先new一个新的数组出来,这里一定不能直接new,要根据原数组的元素类型来new
    	Class componentType = c.getComponentType();
    	Object newArray = Array.newInstance(componentType,newLength);
    	/*
    		arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
    		方法解释:
    			Object src : 原数组
    			int srcPos : 原数据要拷贝的第1个位置
            	Object dest : 目标数组
            	int destPos : 目标数组的粘贴的第1个位置
            	int length  : 从原数组要copy的数组的长度
    	*/
    	System.arrraycopy(obj,0,newArray,0,Math.min(length,newLength));
    	return newArrray;
    }
    
    1. 如果要调用MethodObj.invoke(obj,args...)去激活静态方法,obj置为null
    2. Class对象可以调用Method getMethod(String s,Class...param)来获取Method对象,param代表参数列表的的类型
  • 相关阅读:
    web前端之 CSS
    web前端之 HTML标签详细介绍
    web前端之 HTML介绍
    c++之 scanf 接收用户输入内容
    JQ 全选、全不选
    java 除法向上,向下取整
    Java使用占位符拼接字符串
    eclipse远程debug
    阿里 drds 分布式数据库分节点查询
    Mysql 修改字段长度、修改列名、新增列、修改自增主键起始值
  • 原文地址:https://www.cnblogs.com/doubest/p/12862495.html
Copyright © 2020-2023  润新知