一、软件开发概述 2.1、软件开发的生命周期生命周期:从项目建立到软件停用的过程
问题定义和规划:这个阶段是软件开发人员和需求方的联合讨论,主要确定软件开发目标和可行性需求分析:在确定软件开发可行的情况下,详细分析了软件需要实现的功能 。需求分析阶段是一个非常重要的阶段 。如果这个阶段做得好,将为整个软件开发项目的成功打下良好的基础 。在软件设计:的这个阶段,将整个软件系统分为大大小小的多个模块,并设计了每个模块的具体结构 。比如系统框架设计和数据库设计 。软件设计一般分为总体设计和详细设计 。在程序代码:的这个阶段,软件设计的结果被转换成计算机可执行的程序代码 。在程序编码中,需要制定统一规范的编写规范 。保证程序的可读性和可维护性,提高程序的运行效率 。软件设计完成后,软件测试:要经过严格的测试,找出整个设计过程中存在的问题并加以纠正 。整个测试过程分为三个阶段:单元测试(白盒)、集成测试(黑盒、功能测试、强度性能测试)和系统测试 。主要有两种测试方法:白盒测试和黑盒测试 。在测试过程中,需要建立详细的测试计划,严格按照测试计划进行测试,减少测试的随意性 。运行和维护:来安装和部署软件系统,修复软件中的错误并升级系统 。软件开发完成并投入使用后,由于各种原因,软件无法继续满足用户的要求 。为了延长软件的使用寿命,有必要对软件进行维护 。软件维护包括纠错维护和改进维护 。为了提高软件开发效率,降低软件开发成本,一个优秀的软件系统应该具备以下特征:
-color: #A4A4A4;">可重用性:遵循 DRY(Don't Repeat Yourself Principle) 原则,减少软件中的重复代码 。
包名
全小写 , 域名倒写.模块名.组件名,例如: com.util
接口名
首字母大写,形容词,副词 。习惯性的以 I 开头 。此时的I表示 interface,见名知意.(不强制,要结合其他规范综合考虑),例如: IUserService,IEmployeeService
接口实现类
习惯性使用 Impl 结尾.(不强制,要结合其他规范综合考虑),例如: UserServiceImpl,EmployeeServiceImpl
类名
首字母大写,名词 。遵循驼峰表示法 。例如: User , Employ
方法名
首字母小写 。力求语义清晰,使用多个单词 。遵循驼峰表示法 。例如: getUserInfoByName()
变量名
首字母小写 。遵循驼峰表示法 。例如: userInfo
常量名
全大写,力求语义清晰,使用多个单词 。使用下划线分割 。例如: MAX_STOCK_COUNT.
二、软件测试 软件测试经常分为两类:黑盒测试和白盒测试 。
2.1、黑盒测试 黑盒测试也称功能测试,是通过测试来检测每个功能是否能正常使用,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序的接口上进行测试,检查程序功能是否 按照需求规格说明书 的规定正常使用 。
简单来说就是:不需要写代码,给输入值,看程序是否能够输出期望的值 。他主要发现以下几个错误:
- 功能是否不正确或遗漏
- 界面是否有错误
- 输入和输出错误
- 数据库访问错误
- 性能是否有问题
- 初始化和终止错误等
简单来说就是:需要写代码的 。关注程序具体的执行流程 。2.3、JUnit测试 JUnit 是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework) 。JUnit 测试是程序员测试,即白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能 。
2.3.1、JUnit依赖安装 由于 JUnit 4 回归测试框架是三方提供的,不是 JDK 自带的,所有要使用需导入人家的 jar 包以及安装对应的插件,这里以maven为例,导入maven坐标:
<!-- https://mvnrepository.com/artifact/junit/junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>复制代码
2.3.2、JUnit常用注解 JUnit配上一些常用注解可以解决代码重复的问题2.3.2.1、@Before 修饰的方法会在测试方法之前被自动执行
2.3.2.2、@After 修饰的方法会在测试方法执行之后自动被执行,如果有异常的话,@After后面的代码也会执行
三、配置文件 按理说只要能保存一些配置信息,供程序动态读取数据就OK,但是为了提高效率,在 IT 行业中,习惯使用两种具有特殊特点的文件来作为配置文件
- properties 文件
- XML文件
注意事项:
- 在配置文件中,所有的数据都是字符串,不需要使用引号 。
- 在配置文件中不需要使用空格
文章插图
Properties 是 Map 的实现类.可以继承过来map的常见的操作方法 (get,put....) , map 中的方法,我们一般都不用.因为 properties 文件比较特殊,我们一般使用 Properties 类的新增的方法 。
3.1.2、常见的API
public void load(InputStream inStream);public String getProperty(String key);
package com.test;import java.io.IOException;import java.io.InputStream;import java.util.Properties;/** * @author Xiao_Lin * @date 2020/12/28 11:55 */public class ProTest {public static void main(String[] args) throws IOException {//读取配置文件中的数据Properties properties = new Properties();//为了获取ClassLoder对象,跟Thread无关ClassLoader loader = Thread.currentThread().getContextClassLoader();//通过类加载器去读取配置文件发,返回一个输入流InputStream stream = loader.getResourceAsStream("user.properties");//加载配置文件properties.load(stream);System.out.println(properties.getProperty("user"));System.out.println(properties.getProperty("password"));}}复制代码
3.2、XML文件 XML(Extensible Markup Language),是一种可扩展的标记语言.(使用◇>括起来)XML技术是W3C组织(World Wide Web Consortium万维网联盟)发布的,目前遵循的是W3C组织于1998年发布的 。XML1.0规范.它的设计宗旨是传输数据,而不是显示数据(HTML).它的标签没有被预定义需要自行定义标签.它是W3C的推荐标准 。
3.2.1、为什么要学习XML
- XML是一种通用的数据交换格式 。
- 许多系统的配置文件都是使用XML 。
- JavaEE框架基本都有在使用XML
- XML文档需要在文档第一行声明,声明表示
4.2、字节码对象 Java代码会经历三个阶段:
文章插图
我们可以通过多个实物,发现他们的共性,来抽象成一个类,类就是对象的模板,而一个个的实体就是对象
文章插图
字节码也是真实存在的文件,每一个字节码都是一个实例,而JVM要来存放这些字节码就需要抽象成模板,再通过模板来创建对象,存放每份字节码的信息 。当要使用某份字节码时(比方说创建Person对象),就从JVM中调出存了Person.class内容的Class对象,然后再去实例化Person对象 。3.
JDK中定义好了Class类: java.lang.Class,该类中有大量gte开头的方法,表示可以使用字节码对象来获取信息,所以我们当我们拿到了字节码对象就可以直接操作当前字节码中的构造器、方法、字段等等 。
文章插图
4.3、获取字节码对象 通过API,我们可以得知Class没有公共的构造器,原因是因为Class对象在加载类时由Java虚拟机自动构建 。
方式一
通过Class类的 forName() 方法来获取字节码对象**(常用)**,多用于配置文件,将类名定义在配置文件中 。读取文件,加载类以及各种流行框架中 。
Class.forName(String className);//通过类的全限定名来获取字节码对象,全限定类名是包名+类型Class.forName("java.lang.String");//JVM中存在则返回,不存在就抛出异常 复制代码
方式二通过对象的getClass()方法来获取字节码对象,多用于对象的获取字节码的方式 。
new User().getClass();//通过父类Object中的getClass方法复制代码
方式三通过类型(基本类型)的class字段来获取字节码对象,多用于参数的传递 。
int.class;复制代码
总结- 以上的三种方式第一种是使用最多的,在各种框架中都有使用 。
- 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个 。
@Testpublicvoid testGetClass() throws Exception {// 1 通过类的全限定名 Class.forName();Class clz1 = Class.forName("cn.linstudy.domain.Person");// 2 通过对象的getClass() 方法Person p = new Person();Class clz2 = p.getClass();// 3 通过class 字段去获取Class clz3 = Person.class;// 字节码只会加载一次,所有不管用的哪种方式去获取字节码,都是同一个System.out.println(clz1 == clz2);//trueSystem.out.println(clz2 == clz3);//trueSystem.out.println(clz1 == clz3);//true// int 类型和int数据类型不是同一个System.out.println(int.class);System.out.println(int[].class);}复制代码
4.4、获取构造器 使用反射的目的无外乎是使用程序动态操作类的成员,比如说方法,而且操作方法首先得有对象,而对象是通过构造器来创建的,所以必须先获取构造器 。4.4.1、获取所有构造器 public Constructor<?>[] getConstructors(); :获取 所有public修饰的构造器。
public Constructor<?>[] getDeclaredConstructors(); :获取所有的构造器(包括非public)
4.4.2、获取指定的构造器 public Constructor getConstructor(Class... parameterTypes);
public Constructor getDeclaredConstructor(Class...parameterTypes)
parameterTypes : 参数的类型(构造方法的参数列表的类型).
结论
带着 s 表示获取多个.带着 Declared 表示忽略权限,包括私有的也可以获取到 。
4.4.3、获取构造器练习
@Testpublic void testGetConstructor() throws NoSuchMethodException {// 获取字节码对象Class clz = Person.class;// 1 获取所有 public 构造器Constructor[] cons1 = clz.getConstructors();for(Constructor con : cons1){System.out.println(con);}System.out.println("--------");// 2 获取所有构造器,包括 privateConstructor[] cons2 = clz.getDeclaredConstructors();for(Constructor con : cons2){System.out.println(con);}// 3 获取无参构造器Constructor con1 = clz.getConstructor();System.out.println(con1);// 4 获取带参构造器Constructor con2 = clz.getConstructor(Long.class, String.class);System.out.println(con2);// 5 获取指定 private 构造器Constructor con3 = clz.getDeclaredConstructor(String.class);System.out.println(con3);}复制代码
常见错误参数不匹配,报错.找不到指定的构造器
文章插图
4.4.4、调用构造器创建对象
public Object newInstance(Object... initargs);// initargs: 调用该构造器传递的实际参数.参数列表一定要匹配(类型,个数,顺序).复制代码
@Testpublic void testCreateObject() throws Exception {// 获取字节码对象Class clz = Class.forName("cn.linstudy.domain.Person");// 获取带参数构造器,参数为参数类型Constructor con1 = clz.getConstructor(Long.class, String.class);//调用构造器Object obj = con1.newInstance(1L, "小狼");System.out.println(obj);// 获取带有参数的 private 构造器Constructor con2 = clz.getDeclaredConstructor(String.class);// 调用私有构造器,必须先设置为可访问con2.setAccessible(true);Object obj2 = con2.newInstance("小码");System.out.println(obj2);}复制代码
注意: 不能直接访问没有权限(非public)的成员,如果想要使用反射去操作非public的成员.必须设置一个可以访问的标记. 我们尝试私有化构造器来创建对象,结果被告知权限不够文章插图
解决办法如下:
public void setAccessible(boolean ag) : 传递一个true,表示可以访问,表示不管权限.
文章插图
从 API 中我们可以发现,Constructor,Field,Method 是 AccessibleObject 的子类,因为这三种成员都是可以被访问private 修饰符修饰的 。
package com.test.reflect;import java.lang.reflect.Constructor;/** * @author Xiao_Lin * @date 2020/12/28 20:17 */public class TestReflect {public static void main(String[] args) throws Exception {Class<?> student = Class.forName("com.test.reflect.Student");System.out.println(student);Constructor<?> constructor = student.getDeclaredConstructor(String.class);constructor.setAccessible(true);Object zs = constructor.newInstance("张三");System.out.println(zs);}}复制代码
文章插图
只要看到传入全限定名,基本上都是要使用反射,通过全限定名来获取字节码对象. 只要看到无指定构造器但是能创建对象,基本上都是要通过字节码对象的 newInstance 去创建对象.
4.5、获取方法4.5.1、获取所有方法
public Method[] getMethods();public Method[] getDeclaredMethods();
4.5.2、获取指定的方法- public Method getMethod(String name, Class<?>... parameterTypes);
- public Method getDeclaredMethod(String name, Class<?>... parameterTypes) :name: 方法名,parameterTypes: 当前方法的参数列表的类型注意,要找到某一个指定的方法,必须要使用方法签名才能定位到,而方法签名=方法名+参数列表,经验和获取构造器的经验一样,带着s表示获取多个,带着declared表示忽略访问权限 。
@Testpublicvoid testGetMethod() throws Exception {/**1 获取所有 public 方法,包括父类的2 获取所有方法,包括 private 不包括父类的3 获取指定参数的public 的方法,包括父类的4 获取指定参数的private 方法,不包括父类的**/// 1 获取字节码对象Class clz = Class.forName("cn.linstudy.domain.Person");// 2 获取构造器来创建对象// 3 获取方法//1 获取所有 public 方法,包括父类的Method[] methods = clz.getMethods();for(Method m : methods){System.out.println(m);}System.out.println("---------");//2 获取所有方法,包括 private 不包括父类的Method[] methods2 = clz.getDeclaredMethods();for(Method m : methods2){System.out.println(m);}System.out.println("---------");//3 获取指定参数的 public 的方法,包括父类的Method sayHelloMethod = clz.getMethod("sayHello", String.class);System.out.println(sayHelloMethod);//4 获取指定参数的private 方法,不包括父类的Method doWorkMethod = clz.getDeclaredMethod("doWork", String.class);System.out.println(doWorkMethod);}复制代码
4.6、调用方法public Object invoke(Object obj, Object... args); :obj: 表示调用该方法要作用到那个对象上..
args:调用方法的实际参数方法的返回值表示,调用该方法是否有返回值,如果有就返回,如果没有返回null 。
传统的调用方法
Student t = new Student(1, "张三"); t.sleep(5);// 张三,睡5个小时 。复制代码
使用反射创建对象调用方法Method m = clz.getMethod(“sleep”, int.class);// 找到sleep方法 。m.invoke(obj, 5);// 睡,5个小时 。复制代码
public class Person {private Long id;private String name;public Person() {}public Person(Long id, String name) {this.id = id;this.name = name;}private Person(String name) {this.name = name;}public void sayHello(){System.out.println("hello");}public String sayHello(String name){System.out.println(name + ": hello");return "您好";}public static void sayHello(String name,Long id){System.out.println("调用静态方法");}private void doWork(){System.out.println("doWork");}private void doWork(String name){System.out.println(name + ": doWork");}// getter方法 setter 方法public String toString() {return "Person{" +"id=" + id +", name='" + name + ''' +'}';}}复制代码
@Testpublicvoid testGetMethod() throws Exception {// 1 获取字节码对象Class clz = Class.forName("com.reflect.Person");// 2 获取构造器来创建对象Object obj = clz.newInstance(); // 使用公共的无参数的构造器// 3 获取方法//1 获取所有 public 方法,包括父类的Method[] methods = clz.getMethods();for(Method m : methods){System.out.println(m);}System.out.println("---------");//2 获取所有方法,包括 private 不包括父类的Method[] methods2 = clz.getDeclaredMethods();for(Method m : methods2){System.out.println(m);}System.out.println("---------");//3 获取指定参数的 public 的方法,包括父类的Method sayHelloMethod = clz.getMethod("sayHello", String.class);System.out.println(sayHelloMethod);// 调用方法Object val1 = sayHelloMethod.invoke(obj, "张三");System.out.println("值1:" + val1);//4 获取指定参数的private 方法,不包括父类的Method doWorkMethod = clz.getDeclaredMethod("doWork", String.class);System.out.println(doWorkMethod);// 设置可访问doWorkMethod.setAccessible(true);// 调用私有的方法doWorkMethod.invoke(obj,"李四");// 调用静态方法Method staticSayHelloMethod = clz.getDeclaredMethod("sayHello", String.class, Long.class);// 不需要对象去调用,但是参数必须加上null,不然会把后面的参数作为调用方法的对象了.staticSayHelloMethod.invoke(null,"小明",1L);}复制代码
注意:- 方法也是可以被访问私有修饰符修饰的,所以,如果要访问非 public 修饰的方法,需要在访问之前设置可访问 method.setAccessible(true);。
- 如果调用的是静态方法,是不需要对象的,所以此时在invoke方法的第一个参数,对象直接传递一个 null 即可 。
public Field getDeclaredField(String name);
name 要获取的字段的名称
4.7.2、获取所有字段public Field[];
getFields() ;
public Field[] getDeclaredFields();
@Testpublic void testField() throws Exception {// 1 获取字节码对象Class clz = Person.class;Object obj = clz.newInstance();// 2 获取字段Field[] fs = clz.getFields();for(Field f: fs){System.out.println(f);}Field[] fs2 = clz.getDeclaredFields();for(Field f: fs2){System.out.println(f);}// 获取单个字段Field nameField = clz.getDeclaredField("name");System.out.println(nameField);}复制代码
4.8、操作字段get(Object obj);set(Object obj,Object value);
// 设置私有字段可访问nameField.setAccessible(true);// 操作name字段// 设置那么字段的数据nameField.set(obj,"小狼");// 获取name字段的数据Object nameValue = https://www.dzlps.cn/nameField.get(obj);System.out.println(nameValue);复制代码
五、内省5.1、JavaBean JavaBean 是 Java 中最重要的一个可重用的组件(减少代码重复,可重用,封装业务逻辑,封装数据) 。5.1.1、JavaBean 的规范要求
- 使用 public 修饰 。
- 字段私有化 。
- 提供 get/set 方法 。
- 公共的无参数的构造器(使用反射,使用字节码对象.newInstance去创建对象) 。
- 事件
- 方法
- 属性
属性不是字段,属性是通过get/set方法推导出来的 。
【软件项目阶段划分 项目阶段划分的依据是】 **规范的get方法/获取方法/读方法:**public修饰、无参数、有返回、get开头 。
**规范的set方法/设置方法/写方法:**public修饰、有参数、无返回、set开头 。
注意:
- 只要是标准的get/set方法,就存在属性,不一定非得是通过工具自动生成的规范的写法 。
文章插图
- 字段是 boolean 的,读方法不是 get 开头,而是 is 开头 。
文章插图
5.2、内省的概述 JavaBean是一个非常常用的组件,无外乎就是操作里面的属性 。而之前我们要获取JavaBean中的方法,如果使用反射非常麻烦,于是SUN公司专门提供了一套操作 JavaBean 属性的API: 内省 ( Introspector ) 。
5.3、内省的作用
- 获取到属性名和属性类型等相关状态信息 。
- 获取属性对应的读写方法操作属性的值等操作方式 。
- 通过字节码对象,获取到JavaBean的描述对象,返回 JavaBean的描述对象public static BeanInfo getBeanInfo(Class beanClass, Class stopClass);
- 通过 JavaBean 描述对象获取属性描述器PropertyDescriptor[] getPropertyDescriptors();
- 通过属性描述器,获取到属性名、属性类型、读写(getter/setter)方法获取属性名: public String getName();获取属性类型: public Class<?> getPropertyType();获取读方法(getter): public Method getReadMethod();获取写方法(setter): public Method getWriteMethod();
文章插图
示范: BeanInfo beanInfo = Introspector.getBeanInfo(Person.class,Object.class);
package com.day03.IntrospectorDemo;import java.beans.BeanInfo;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;/** * @author Xiao_Lin * @date 2020/12/29 13:37 */public class TestIntrospector {public static void main(String[] args) throws Exception {//创建对象Student student = Student.class.newInstance();//把 JavaBean 转成 beanInfoBeanInfo beanInfo = Introspector.getBeanInfo(student.getClass(),Object.class);//通过通过beanInfo获取所有属性PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();//遍历属性描述器数组,获取到每个属性描述器for (PropertyDescriptor pd : propertyDescriptors) {//获取属性名System.out.println("属性名 = " + pd.getName());//获取属性类型System.out.println("属性类型 = " + pd.getPropertyType());//获取属性的getter/setter方法Method getMethod = pd.getReadMethod();System.out.println("get方法 = " +getMethod);Method setMethod = pd.getWriteMethod();System.out.println("set方法 = " +setMethod);//调用age属性的set方法if ("age".equals(pd.getName())){//执行age的set方法,invoke参数含义是给哪个对象赋予哪个值setMethod.invoke(student,22);}//再次执行get方法System.out.println(student.getAge());}}}复制代码
5.5、JavaBean 和 Map 之间的转化 map和JavaBean的结构很类似,我们可以将 map 和 JavaBean 相互转换.将key和属性名一 一对应起来文章插图
5.5.1、JavaBean转map
// Javabean 转 mappublic static Map<String, Object> BeanToMap(Object obj) throws Exception{Map<String, Object> map = new HashMap<>();//通过内省获得所有属性BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();for (PropertyDescriptor pd : pds) {//获取属性名作为keyString key = pd.getName();//获取属性的getter方法并且调用Object value = https://www.dzlps.cn/pd.getReadMethod().invoke(obj);map.put(key, value);}return map;}复制代码
public class BeanMap {public static void main(String[] args) throws Exception{Map<String, Object> map = BeanToMap(new Student("张三", 20));map.forEach((k,v)-> System.out.println(k+"->"+v));}}复制代码
文章插图
5.5.2、map转JavaBean
//map转JaveBean,这里使用泛型public static <T> TMapToBean(Map<String, Object> map ,Class<T> clz) throws Exception{//创建JavaBean对象T t = clz.newInstance();//遍历属性,获取属性名作为mao的key 去获取value值,再设置给setter方法//获取所有属性BeanInfo beanInfo = Introspector.getBeanInfo(clz, Object.class);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();for (PropertyDescriptor pd : pds) {String key = pd.getName();Object value = https://www.dzlps.cn/map.get(key);pd.getWriteMethod().invoke(t,value);}return t;}复制代码
文章插图
六、注解6.1、注解介绍 我们可以使用注解来修饰类中的成员信息,注解其实就是Annotation 。
文章插图
6.2、定义格式
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface 注解名 {}复制代码
定义格式: @interface 注解名使用格式: @注解名(属性名=属性值, 属性名=属性值)
注解贴在程序元素上,想要拥有某一些功能,必须有三个角色去参与 :
- 注解本身
- 被贴的程序元素
- 第三方程序,使用反射给注解赋予功能(在注解的背后,一定有一段代码给注解赋予功能) 。
@Override@Deprecated@SuppressWarings@Functionallnterface
6.4、元注解 注解 :用来贴在类/方法/变量等之上的一个标记,第三方程序可以通过这个标记赋予一定功能 。元注解 :在定义注解的时候用来贴在注解上的注解,用来限定注解的用法 。他囊括了三个注解
6.4.1、@Target 表示注解可以贴在哪些位置(类,方法上,构造器上等等).位置的常量封装在 ElementType 枚举类 中 。
ElementType.ANNOTATION_TYPEElementType.CONSTRUCTORElementType.FIELDElementType.LOCAL_VARIABLEElementType.METHODElementType.PACKAGEElementType.PARAMETERElementType.TYPE
6.4.2、@Retention 表示注解可以保存在哪一个时期,表示时期的值,封装在RetentionPolicy枚举类中 。文章插图
6.4.3、@Documented 使用 @Documented 标注的标签会保存到API文档中 。
6.4.4、@Inherited @Inherited 标注的标签可以被子类所继承 。
标记已过时,不推荐使用.在JDK5之前,使用文档注释来标记过时
@SuppressWarings@Functionallnterface
6.4、元注解 注解 :用来贴在类/方法/变量等之上的一个标记,第三方程序可以通过这个标记赋予一定功能 。元注解 :在定义注解的时候用来贴在注解上的注解,用来限定注解的用法 。他囊括了三个注解
6.4.1、@Target 表示注解可以贴在哪些位置(类,方法上,构造器上等等).位置的常量封装在 ElementType 枚举类 中 。
ElementType.ANNOTATION_TYPEElementType.CONSTRUCTORElementType.FIELDElementType.LOCAL_VARIABLEElementType.METHODElementType.PACKAGEElementType.PARAMETERElementType.TYPE
6.4.2、@Retention 表示注解可以保存在哪一个时期,表示时期的值,封装在RetentionPolicy枚举类中 。文章插图
6.4.3、@Documented 使用 @Documented 标注的标签会保存到API文档中 。
6.4.4、@Inherited @Inherited 标注的标签可以被子类所继承 。
原文链接:https://juejin.cn/post/6985364060472606733如果觉得本文对你有帮助,可以转发关注支持一下
- 千元小成本创业项目 千元小本创业
- 22种无本钱做什么赚钱 小投资赚钱项目手工
- 项目编码的组成 项目工程编号怎么写
- EPC 工程总承包项目经理,总承包项目经理证有用吗
- 红米手机|腾讯一年关闭超40个项目,被内部贪腐掏空?
- 项目变更流程 项目范围变更的主要原因
- 大学生创新创业活动,互联网 大学生创新创业项目名称
- 连锁加盟好项目 今年加盟创业项目
- 项目计划书模板,餐厅投标计划书
- wbs分解简单案例,施工工程项目wbs分解图