1,可变长度参数
语法:类型... (注意:一定是3个点)
可变长度参数要求参数个数是:0-N个。
可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个。
可变长度参数可以当做一个数组来看
代码示例
public class ArgsTest {
public static void main(String[] args) {
m(100,"abc");
m(200,"abc","def","xyz");
// 传数组
String[] strings = {"我","是","中","国","人"};
m(300,strings);
}
public static void m(int a, String... args){
System.out.println(a);
// args有length属性,说明args是一个数组
// 可以将可变长度参数当做一个数组来看。
for (int i = 0;i < args.length;i++){
System.out.println(args[i]);
}
}
}
2,反射方法Method(了解内容)
2.1,通过反射机制获取一个对象的方法
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectTest08 {
public static void main(String[] args) throws Exception {
Class us = Class.forName("com.javaSE.reflects.UserService");
// 获取所有的Method(包括私有的)
Method[] methods = us.getDeclaredMethods();
// 遍历Method
for (Method method : methods){
// 获取修饰符列表
System.out.println("修饰符列表:" + Modifier.toString(method.getModifiers()));
// 获取方法返回值类型
System.out.println("返回值类型:" + method.getReturnType().getName());
// 获取方法名
System.out.println("方法名:" + method.getName());
// 获取方法的参数列表
Class[] parameterTypes = method.getParameterTypes();
for (Class pt : parameterTypes){
// 获取参数类型名字
System.out.println("参数类型名字:" + pt.getSimpleName());
}
}
System.out.println("-------------通过反射机制,反编译一个类的方法---------------------------------------------");
// 通过反射机制,反编译一个类的方法Method
fbyMethod();
}
private static void fbyMethod() throws ClassNotFoundException {
Class us = Class.forName("com.javaSE.reflects.UserService");
// 创建可变字符串对象
StringBuilder sr = new StringBuilder();
sr.append(Modifier.toString(us.getModifiers()) + " class " + us.getSimpleName() + "{\n");
// 获取所有的Method(包括私有的)
Method[] methods = us.getDeclaredMethods();
for (Method method : methods){
sr.append("\t");
sr.append(Modifier.toString(method.getModifiers()));
sr.append(" ");
sr.append(method.getReturnType().getSimpleName());
sr.append(" ");
sr.append(method.getName());
sr.append("(");
for (Class c : method.getParameterTypes()) {
sr.append(c.getSimpleName());
sr.append(",");
}
// 删除指定下标位置的字符
sr.deleteCharAt(sr.length() - 1);
sr.append("){\n");
sr.append("\t}");
sr.append("\n");
}
sr.append("}");
System.out.println(sr);
}
}
class UserService{
/**
* 登录方法
* @param name 用户名
* @param password 密码
* @return true登录成功,false登录失败。
*/
public boolean login(String name ,String password){
if ("admin".equals(name) && "123".equals(password)){
return true;
}
return false;
}
/**
* 退出登录
*/
public void loginOut(){
System.out.println("已成功退出登录!");
}
}
2.2,通过反射机制调用一个对象的方法
import java.lang.reflect.Method;
public class ReflectTest09 {
public static void main(String[] args) throws Exception {
Class us = Class.forName("com.javaSE.reflects.UserService");
// 创建对象
Object obj = us.newInstance();
// 获取UserService对象的方法Method
Method loginM = obj.getClass().getDeclaredMethod("login",String.class,String.class);
// 调用方法
Object invKV = loginM.invoke(obj,"admin","123");
System.out.println(invKV);
}
}
反射构造方法
- 通过反射机制,获取一个类的父类
- 通过反射机制,获取一个类实现的所有接口
- 通过反射机制,调用一个类的构造方法
- 通过反射机制,反编译一个类的构造方法
代码示例
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class ReflectTest10 {
public static void main(String[] args) throws Exception{
// 创建VipUser对象
Class cc = Class.forName("com.javaSE.reflects.VipUser");
System.out.println("-------------通过反射机制,获取一个类的父类---------------------------------------------");
Class superClass = cc.getSuperclass();
// 获取父类名字
System.out.println(superClass.getName());
System.out.println(superClass.getSimpleName());
System.out.println("-------------通过反射机制,获取一个类实现的所有接口---------------------------------------------");
Class strClass = Class.forName("java.lang.String");
// 获取一个类实现的所有接口
Class[] interfaces = strClass.getInterfaces();
for (Class i : interfaces){
System.out.println(i.getName());
}
System.out.println("-------------通过反射机制,调用一个类的构造方法---------------------------------------------");
// 调用无参构造方法
Object obj0 = cc.newInstance();
System.out.println(obj0);
// 获取无参构造方法
Constructor c0 = cc.getDeclaredConstructor();
Object obj00 = c0.newInstance();
System.out.println(obj00);
// 获取带有参数的构造方法
Constructor c1 = cc.getDeclaredConstructor(int.class);
Constructor c2 = cc.getDeclaredConstructor(int.class,String.class);
Constructor c3 = cc.getDeclaredConstructor(int.class,String.class,String.class);
Constructor c4 = cc.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
// 调用构造方法new对象
Object obj1 = c1.newInstance(112);
Object obj2 = c2.newInstance(112,"admin");
Object obj3 = c3.newInstance(112,"admin","2020-02-20");
Object obj4 = c4.newInstance(112,"admin","2020-02-20",true);
// 打印输出
System.out.println(obj1);
System.out.println(obj2);
System.out.println(obj3);
System.out.println(obj4);
System.out.println("-------------通过反射机制,反编译一个类的构造方法---------------------------------------------");
// 创建可变字符串对象
StringBuilder sr = new StringBuilder();
sr.append(Modifier.toString(cc.getModifiers()) + " class " + cc.getSimpleName() + "{\n");
// 拼接构造方法
Constructor[] cs = cc.getDeclaredConstructors();
for (Constructor c : cs){
sr.append("\t");
sr.append(Modifier.toString(c.getModifiers()));
sr.append(" ");
sr.append(cc.getSimpleName());
sr.append("(");
// 拼接参数
for (Class cp : c.getParameterTypes()){
sr.append(cp.getSimpleName());
sr.append(",");
}
if (c.getParameterTypes().length > 0){
sr.deleteCharAt(sr.length() - 1);
}
sr.append("){}\n");
}
sr.append("}");
System.out.println(sr);
}
}
class VipUser{
int no;
String name;
String birth;
boolean sex;
public VipUser() {
}
public VipUser(int no) {
this.no = no;
}
public VipUser(int no, String name) {
this.no = no;
this.name = name;
}
public VipUser(int no, String name, String birth) {
this.no = no;
this.name = name;
this.birth = birth;
}
public VipUser(int no, String name, String birth, boolean sex) {
this.no = no;
this.name = name;
this.birth = birth;
this.sex = sex;
}
@Override
public String toString() {
return "VipUser{" +
"no=" + no +
", name='" + name + '\'' +
", birth='" + birth + '\'' +
", sex=" + sex +
'}';
}
}
3,注解
1,注解:或者叫做注释,英文单词:Annotation
2,注释Annotation是一种引用数据类型;编译之后也是生成.class文件
-
3,怎么自定义注解,语法格式
- [修饰符列表] @interface 注解类型名{}
-
4,注解怎么使用,用在什么地方
- 1,注解使用是的语法结构:
@注解类型名 - 2,注解可以用在类上、属性上、方法上、变量上...等;注解还可以出现在注解类型上。
- 3,注解中的属性是value,并且只有一个属性,该属性名可以省略不写。
- 4,注解中属性是数组,数组中只有一个元素,大括号可以省略不写。
- 1,注解使用是的语法结构:
-
5,注解当中的属性类型:
- byte,short,int,long,float,double,boolean,char,String,class,枚举类型以及以上每一种的数组形式。
-
6,关于jdk lang包下的Override注解
- 这个注解只能注释方法,是给编译器参考的,和运行阶段没关系;
- 凡是java中带有这个注解的方法,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器报错。
7,元注解:用来标注"注解类型"的"注解",称为元注解。
-
8,常见的元注解类型
-
Target:用来标注"被标注的注解"可以出现在哪些位置上。
- @Target(ElementType.METHOD) 表示"被标注的注解"只能出现在方法上。
-
Retention:用来标注"被标注的注解"最终保存在哪里。
- @Retention(RetentionPolicy.SOURCE) 表示该注解只能被保留在java源文件中。
- @Retention(RetentionPolicy.CLASS) 表示该注解被保留在class文件中。
- @Retention(RetentionPolicy.RUNTIME) 表示该注解被保留在class文件中,并且可以被反射机制所读取。
-
Deprecated注解:表示标注的内容已过时。
- 这个注解主要是向其他程序员传递一个信息,告知已过时,有更好的解决方案存在。
-
代码示例
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
public class AnnotationTest01 {
/*
报错了:如果一个注释当中有属性,那么必须给属性赋值(除非该属性使用了default指定了默认值)
@MyAnnotation
public void doSome(){
}
*/
// @MyAnnotation(属性名=属性值)
// 需给属性赋值
@MyAnnotation(name = "a",color = "red")
public void doSome(){
}
// 注解中的属性是value,并且只有一个属性,该属性名可以省略不写
// @AnnotationValue(value = "a")
@AnnotationValue("a")
public void doOther(){
}
public static void main(String[] args) throws Exception {
// 获取被注解的类
Class c = Class.forName("com.javaSE.annotation.MyAnnotationTest");
//========通过反射机制,反射类注解==========================================================================
// 判断类上面是否有@MyAnnotation2注解
System.out.println(c.isAnnotationPresent(AnnotationValue.class));// true
if (c.isAnnotationPresent(AnnotationValue.class)){
AnnotationValue av = (AnnotationValue)c.getAnnotation(AnnotationValue.class);
System.out.println("类上面的注解对象:" + av);
// 获取注解对象的属性
String value = av.value();
System.out.println(value);
}
//========通过反射机制,反射方法注解==========================================================================
Method method = c.getDeclaredMethod("doSome");
// 判断该方法上是否存在注解
if (method.isAnnotationPresent(MyAnnotation2.class)){
MyAnnotation2 ma2 = (MyAnnotation2)method.getAnnotation(MyAnnotation2.class);
System.out.println("name:" + ma2.name() + ";password:" + ma2.password());
}
}
}
@AnnotationValue("测试反射类注解")
class MyAnnotationTest{
@MyAnnotation2(name = "admin",password = "123")
public void doSome(){
}
}
/**
* Target:只允许该注解可以标注类、方法
* Retention:这个注解可以被反射
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
String name();
String password();
}
/**
* Target:只允许该注解可以标注类、方法
* Retention:这个注解可以被反射
* value属性的注解
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationValue{
String value();
}
@interface MyAnnotation {
/**
* 在注解中定义属性,一下这个是MyAnnotation的name属性
* 看着像一个方法,实际上是属性
* @return
*/
String name();
String color();
int age() default 24; // 属性指定默认值
}
4,开发中如何使用注解
需求:假设有一个注解叫做:Uid;这个注解只能出现在类上面,当这个类上有这个注解的时候,
要求这个类中必须有一个int类型的uid属性,如果没有这个属性就报异常,如果有正常执行。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
public class AnnotationTest02 {
public static void main(String[] args) throws Exception {
// 获取类
Class uc = Class.forName("com.javaSE.annotation.User");
boolean isOk = false; // 设置一个默认boolean标记
// 判断类上是否有Uid注解
if (uc.isAnnotationPresent(Uid.class)){
// 有Uid注解 要求必须存在int类型的uid属性
// 获取类的属性
Field[] fields = uc.getDeclaredFields();
for (Field field : fields){
// 表示这个类的是合法的类,有@Uid注解,类中存在int类型的uid
if ("uid".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
isOk = true;// 表示合法
break;
}
}
// 判断是否合法
if (!isOk){//不合法
throw new HasNotUidPropertyException("被@Uid注解的类必须要有一个int类型的uid属性");
}
}
}
}
/*
自定义异常
*/
class HasNotUidPropertyException extends RuntimeException{
public HasNotUidPropertyException() {
}
public HasNotUidPropertyException(String message) {
super(message);
}
}
/*
自定对象
*/
@Uid
class User{
// int uid;
String name;
String password;
}
/**
* Target:只允许该注解可以标注类
* Retention:这个注解可以被反射
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Uid{
}
上篇:JavaSE进阶十一 反射机制一