java基础语法

##java基础语法
###重写

  • 参数列表与被重写方法的参数列表必须完全相同。

  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。

  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。

  • 父类的成员方法只能被它的子类重写。

  • 声明为 final 的方法不能被重写。

  • 声明为 static 的方法不能被重写,但是能够被再次声明。

  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。

  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。

  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。

  • 构造方法不能被重写。

  • 如果不能继承一个类,则不能重写该类的方法。

##java反射
###反射基本概念
官方概念:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取、调用对象方法的功能称为java语言的反射机制。

反射是通过Class对象(字节码文件),来知道某个类的所有属性和方法。也就是说通过反射我们可以获取构造器,对象,属性,方法(原本不知道)
我的理解:就是获取实例化对象的原本的class。那么此时我们获取到他原本的class以后,想要获取其属性,方法就很容易了。
###获取Class对象
####通过该类的对象获取对应的Class对象

public static void main(String[] args) throws Exception{
person p=new person("test");
Class a = p.getClass();
System.out.println(a);
}

####通过类名.class静态属性

Class stuClass2 = Student.class;
System.out.println("是否为同一个class对象?"+(stuClass==stuClass2));

虽然比较简单,但是需要导包,不然会编译错误
####通过Class类中的静态方法forName()方法获取

public static void main(String[] args) throws Exception{
person p=new person("test");
Class a =Class.forName("person");
System.out.println(a);
}


###获取有参构造方法
####getConstructor()

public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return getConstructor0(parameterTypes, Member.PUBLIC);
}

这里解释一下,
1.首先传出的类型和Constructor有关,这个<T>指的是泛型,意思是传入的类型又右边的数据类型决定
2.后面可以发现,他传入的数据类型要求是一个class类,那么我们这里其实可以这样构造

import java.io.*;
import java.lang.reflect.Constructor;

public class Main {
public static void serialize(final Object obj) throws Exception{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(obj);
}
public static void main(String[] args) throws Exception{
person p=new person("test");
Class a =Class.forName("person");
Constructor personconstructor=a.getConstructor(String.class);
person pe1=(person) personconstructor.newInstance("aaa");
System.out.println(pe1);

}
}


有几个点解释一下:

  • newInstance() 是java反射框架中类对象(Class)创建新对象的方法
  • 现在获取到person这个原型Class,然后我们想要实例化对象出来(也就是利用),此时我们可以单纯使用newInstance,但是这样的话,此时调用的是person类的无参构造方法
    public static void main(String[] args) throws Exception{
    person p=new person("test");
    Class a =Class.forName("person");
    person pe1=(person) a.newInstance();
    }
  • 可以使用getConstructor获取其有参构造方法,而里面的参数由于要求写的是类,所以我们的写法是String.class,即通过类名.class静态属性获取其原型Class进行穿参写入
  • 接下来再使用newInstance创建的就是有参的对象了
    ###获取类里面的属性
    ####getFields()&getDeclaredFields()
    这两个就是打印当前类里面的所有属性,但是加上Declared以后其私有属性也将会被打印出来
     public static void main(String[] args) throws Exception{
    person p=new person("test",22);
    Class a =Class.forName("person");
    // Constructor personconstructor=a.getConstructor(String.class);
    // person pe1=(person) personconstructor.newInstance("aaa");
    // System.out.println(pe1);
    person pe1=(person) a.newInstance();

    Field[] persof=a.getFields();
    // Field[] persof=a.getDeclaredFields();
    for(Field f:persof){
    System.out.println(f);
    }
    }
    ####getField()&getDeclaredField()

更改public属性:

    public static void main(String[] args) throws Exception{
person p=new person("test",22);
Class a =Class.forName("person");
// Constructor personconstructor=a.getConstructor(String.class);
// person pe1=(person) personconstructor.newInstance("aaa");
// System.out.println(pe1);
//person pe1=(person) a.newInstance();

Field persof=a.getField("age");
// Field[] persof=a.getDeclaredFields();
// for(Field f:persof){
// System.out.println(f);
// }
persof.set(p,23);
System.out.println(p);

}

  • 使用set进行赋值操作,可以看到他的参数为obj和value,也就是说我们需要对一个对象进行赋值操作

更改private属性:

    public static void main(String[] args) throws Exception{
person p=new person("test",22);
Class a =Class.forName("person");
// Constructor personconstructor=a.getConstructor(String.class);
// person pe1=(person) personconstructor.newInstance("aaa");
// System.out.println(pe1);
//person pe1=(person) a.newInstance();

Field persof=a.getDeclaredField("name");
persof.setAccessible(true);
// Field[] persof=a.getDeclaredFields();
// for(Field f:persof){
// System.out.println(f);
// }
Field persof1=a.getField("age");
persof.set(p,"aaa");
persof1.set(p,25);
System.out.println(p);

}
  • 只需要使用getDeclaredField,并且加上setAccessible(true)
    ###获取类的方法
    ####getDeclaredMethod()/getMethod()

    Method perMethod=a.getMethod("getName");
    System.out.println(perMethod.invoke(p))
  • 和上面获取属性的用法类似

  • 这里需要使用invoke来启动这个方法

  • 调用有参方法,需要写清楚类型

    Method perMethod=a.getMethod("getName", String.class);
    System.out.println(perMethod.invoke(p,"abcd"));

  • 获取private方法,也只需要加上perMethod.setAccessible(true)即可触发
    ##java代理
    ###java静态代理
    若类中方法较多,则静态代理类中需要重写的方法也较多

    public class UserProxy implements IUser {
    IUser user;
    public UserProxy(){}
    public UserProxy(IUser user){this.user = user;}

    @Override
    public void show() {
    user.show();
    System.out.println("调用了show");
    }
    }

    ###java动态代理
    ####构造过程
    demo
    main.java:

    public class ProxyTest {
    public static void main(String[] args) {
    IUser user=new UserImpl();
    //user.show();


    //静态代理
    // IUser userproxy = new UserProxy();
    // userproxy.show();
    InvocationHandler userInvocationHandler = new UserInvocationHandler(user);
    IUser userproxy = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(),userInvocationHandler);
    userproxy.show();


    }
    }

    UserinvocationHandler:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;

    public class UserInvocationHandler implements InvocationHandler {
    IUser user;

    public UserInvocationHandler(IUser user){
    this.user = user;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    method.invoke(user,args);
    return null;
    }
    }
  • 动态代理利用的是java中的Proxy类来进行代理,其参数由三部分组成,其中最主要的是要自定义一个InvocationHandler,并通过重写其invoke方法来进行动态代理调用,从而弥补静态代理过程中如果有多个方法,需要重写多个方法的缺陷

  • 动态代理使用过程中,除了一开始创建InvocationHandler的时候调用的是InvocationHandler接口,其他的都是属于你所要调用的类的接口,例如这个demo中是IUser,所以后面写的都是IUser
    ####意义
    代理的意义,其实就是不修改原有的类,但是增加了其功能
    ##java类加载机制
    ###类加载的时候会执行代码情况
    初始化:静态代码块
    实例化:构造代码块,无参构造函数
    ####动态类加载方法
    Classloader将字节流加载到内存,并使用defineClass加载到JVM生成可以被调用的类。Java源码编译之后生成对应的字节码,字节码的存储形式不只局限于文件,还可以使用访问数据库,URL请求的方式进行获取。存储的字节码还可以使用加密算法进行加密,提高存储安全性

  • 1.Class.forName 不能加载原生类型,但其他类型都是支持的

  • 2.Classloader.loadclass 不能加载原生类型和数组类型,其他类型都是支持的
    Class.forname
    ClassLoader->SecureClassLoader->URLClassLoader->AppClassLoader

LoadClass->findClass(重写的方法)->defineClass(从字节码加载类)

public class LoadClassTest {
public static void main(String[] args) throws Exception{

URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("")} );
Class<?> c = urlClassLoader.loadClass("Hello");
c.newInstance();

}
}

defineClass重载加载字节码

public class LoadClassTest {
public static void main(String[] args) throws NoSuchMethodException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException {
ClassLoader cl = ClassLoader.getSystemClassLoader();
Method defineClassMethod= ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("Class文件路径"));
Class c = (Class) defineClassMethod.invoke(cl,"要加载的类的名称",code,0,code.length);
c.newInstance();

}
}

unsafe实现动态类加载

Class c = Unsafe.class;
Field theUnsafeField = c.getDeclaredField("theUnsafe");
theUnsafeField.setAccess
Author

vague huang

Posted on

2022-12-02

Updated on

2023-02-10

Licensed under

Comments