JavaSE高阶篇-反射

第一部分、Junit单元测试

1)介绍

1.概述:Junit是一个单元测试框架,在一定程度上可以代替main方法,可以单独去执行一个方法,测试该方法是否能跑通,但是Junit是第三方工具,所以使用之前需要导入jar包

2)Junit的基本使用(重点啊)

1.导入Junit的jar包
2.定义一个方法,在方法上写注解:  @Test
3.执行方法:
  a.点击该方法左边的绿色按钮,点击run执行 -> 单独执行一个指定的方法
  b.如果想要执行所有带@Test的方法,点击类名左边绿色按钮,点击run执行-> 执行当前类中所有@Test的方法

public class Demo01Junit {
    @Test
   public void add(){
       System.out.println("我是@Test执行的add方法");
   }

   @Test
   public void delete(){
       System.out.println("我是@Test执行的delete方法");
   }
}

 3)Junit的注意事项

1.@Test不能修饰static方法
2.@Test不能修饰带参数方法
3.@Test不能修饰带返回值方法 

 4)Junit的相关注解

@Before:在@Test之前执行,有多少个@Test执行,@Before就执行多少次 -> 一般都是用作初始化变量
@After:在@Test之后执行,有多少个@Test执行,@After就执行多少次   -> 一般可以用作关闭资源

public class Demo01Junit {
    @Test
    public void add() {
        System.out.println("我是@Test执行的add方法");
    }

    @Test
    public void delete() {
        System.out.println("我是@Test执行的delete方法");
    }

    @Before
    public void methodBefore() {
        System.out.println("我是@Before执行的方法");
    }

    @After
    public void methodAfter() {
        System.out.println("我是@After执行的方法");
    }
}

5)@Test以后怎么使用

/**
 * 此类专门去测我们写好的功能
 */
public class Demo02Junit {
   /* public static void main(String[] args) {
        CategoryController cc = new CategoryController();
        int result = cc.add("蔬菜");
        System.out.println("result = " + result);

        List<String> list = cc.findAllCategory();
        System.out.println(list);
    }*/

    /**
     * 此方法专门测添加功能
     */
    @Test
    public void add(){
        CategoryController cc = new CategoryController();
        int result = cc.add("蔬菜");
        System.out.println("result = " + result);
    }

    /**
     * 此方法专门测查找功能
     */
    @Test
    public void find(){
        CategoryController cc = new CategoryController();
        List<String> list = cc.findAllCategory();
        System.out.println(list);
    }
}
public class CategoryController {
    /**
     * 添加功能
     */
    public int add(String categoryName){
        ArrayList<String> list = new ArrayList<>();
        list.add(categoryName);
        return 1;//如果返回一个1,证明添加成功了
    }

    /**
     * 查找功能
     */
    public List<String> findAllCategory(){
        ArrayList<String> list = new ArrayList<>();
        list.add("蔬菜");
        list.add("水果");
        list.add("服装");
        list.add("电器");
        list.add("玩具");
        list.add("手机");
        return list;
    }
}

 扩展注解:

@BeforeClass:在@Test之前执行,只执行一次,可以修饰静态方法

@AfterClass:在@Test之后执行,只执行一次,可以修饰静态方法

public class Demo03Junit {
 @Test
 public void add() {
     System.out.println("我是@Test执行的add方法");
 }

 @Test
 public void delete() {
     System.out.println("我是@Test执行的delete方法");
 }

 @BeforeClass
 public static void methodBefore() {
     System.out.println("我是@Before执行的方法");
 }

 @AfterClass
 public static void methodAfter() {
     System.out.println("我是@After执行的方法");
 }
}

 第二部分、类的加载时机

1.new对象
2.new子类对象(new子类对象先初始化父类)
3.执行main方法
4.调用静态成员
5.反射,创建Class对象   

1.类加载器(了解)_ClassLoader

1.概述:
   在jvm中,负责将本地上的class文件加载到内存的对象_ClassLoader
2.分类:
   BootStrapClassLoader:根类加载器->C语言写的,我们是获取不到的
                        也称之为引导类加载器,负责Java的核心类加载的
                        比如:System,String等
                        jre/lib/rt.jar下的类都是核心类
   ExtClassLoader:扩展类加载器
                  负责jre的扩展目录中的jar包的加载
                  在jdk中jre的lib目录下的ext目录
   AppClassLoader:系统类加载器
                  负责在jvm启动时加载来自java命令的class文件(自定义类),以及classPath环境变量所指定的jar包(第三方jar包)
        
    不同的类加载器负责加载不同的类
       
3.三者的关系(从类加载机制层面):AppClassLoader的父类加载器是ExtClassLoader
            ExtClassLoader的父类加载器是BootStrapClassLoader
 
  但是:他们从代码级别上来看,没有子父类继承关系->他们都有一个共同的父类->ClassLoader

4.获取类加载器对象:getClassLoader()是Class对象中的方法
  类名.class.getClassLoader()
 
5.获取类加载器对象对应的父类加载器
  ClassLoader类中的方法:ClassLoader      
  getParent()->没啥用
      
6.双亲委派(全盘负责委托机制)

   a.Person类中有一个String
     Person本身是AppClassLoader加载
     String是BootStrapClassLoader加载
   b.加载顺序:
     Person本身是App加载,按道理来说String也是App加载
     但是App加载String的时候,先问一问Ext,说:Ext你加载这个String吗?
     Ext说:我不加载,我负责加载的是扩展类,但是app你别着急,我问问我爹去->boot
     Ext说:boot,你加载String吗?
     boot说:正好我加载核心类,行吧,我加载吧!
         
   =======================================================================
         
    比如:
      class Test{
          new Person()
      }

    a.Test是app加载,person按理来说也是app加载,但是app先问ext要不要加载
      ext说不负责加载自定义类,我找boot去,boot一看,我不负责加载自定义类->perosn
      app一看,两个爹都不加载,我自己加载
      
    b.结论:当一个类加载器加载类的时候,总会先去上一级问一问,问上一级要不要加载,如果上级不加载,才自己加载
    
    =======================================================================
7.类加载器的cache(缓存)机制(扩展):一个类加载到内存之后,缓存中也会保存一份儿,后面如果再使用此类,如果缓存中保存了这个类,就直接返回他,如果没有才加载这个类.下一次如果有其他类在使用的时候就不会重新加载了,直接去缓存中拿,保证了类在内存中的唯一性
     
8.所以:类加载器的双亲委派和缓存机制共同造就了加载类的特点:保证了类在内存中的唯一性   

 

public class Demo01ClassLoader {
    public static void main(String[] args) {
        app();
        //ext();
        //boot();
    }

    /**
     * 负责加载核心类
     * BootStrapClassLoader:C语言编写,我们是获取不到的
     */
    private static void boot() {
        ClassLoader classLoader = String.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);
    }

    /**
     * 负责加载扩展类
     */
    private static void ext() {
        ClassLoader classLoader = DNSNameService.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);
    }

    /**
     * 负责加载自定义类
     */
    private static void app() {
        ClassLoader classLoader = Demo01ClassLoader.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);

        ClassLoader parent = classLoader.getParent();
        System.out.println("parent = " + parent);

        ClassLoader parent1 = parent.getParent();
        System.out.println("parent1 = " + parent1);//null
    }
}

 第三部分、反射

1)class类的以及class对象的介绍以及反射介绍

1.反射:是一种解剖class对象的技术
2.能解剖出点啥来?
   a.成员变量 -> 赋值取值
   b.构造方法 -> new对象
   c.成员方法 -> 调用执行

3.反射的作用:写出来的代码更灵活,通用
4.怎么学反射:先把反射技术看成是一套纯API来学
   根据涛哥设计的案例去体会反射代码的通用性

5.反射是解剖class对象的,所以玩儿反射第一步要干啥?
   获取class对象
    
    
6.class对象:class文件对应的对象
  class类:描述class对象的类叫做class类

 2)反射之获取Class对象

1.方式1:调用Object中的getClass()方法:
        Class<?> getClass()
            
2.方式2:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
    
3.方式3:Class类中的静态方法:
       static Class<?> forName(String className)  
                               className:类的全限定名(包名.类名)

public class Person {
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    //私有构造
    private Person(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 

public class Test01 {
    public static void main(String[] args)throws Exception {
        /*
          1.方式1:调用Object中的getClass()方法:
                  Class<?> getClass()
         */
        Person person = new Person();
        Class aClass = person.getClass();
        System.out.println("aClass = " + aClass);

        System.out.println("===================");

        //2.方式2:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
        Class<Person> aClass1 = Person.class;
        System.out.println("aClass1 = " + aClass1);

        System.out.println("===================");

        /*
         3.方式3:Class类中的静态方法:
               static Class<?> forName(String className)
                               className:类的全限定名(包名.类名)
         */
        Class<?> aClass2 = Class.forName("com.atguigu.c_reflect.Person");
        System.out.println("aClass2 = " + aClass2);

        System.out.println("===================");

        //System.out.println(aClass1==aClass2);

    }
}

三种获取Class对象的方式最通用的一种

1.static Class<?> forName(String className)  
                               className:类的全限定名(包名.类名)
2.原因:参数为String形式,可以和Properties文件结合使用

 

className=com.atguigu.c_reflect.Student
public class Test02 {
    public static void main(String[] args)throws Exception {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("day22_reflect\\pro.properties");
        properties.load(in);

        String className = properties.getProperty("className");

        Class<?> aClass = Class.forName(className);
        System.out.println("aClass = " + aClass);
    }
}

 3)获取Class对象中的构造方法

(1)获取所有public中的构造方法

1.Class类中的方法:
  Constructor<?>[] getConstructors() -> 获取的所有public的构造

public class Test02 {
    public static void main(String[] args)throws Exception {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("day22_reflect\\pro.properties");
        properties.load(in);

        String className = properties.getProperty("className");

        Class<?> aClass = Class.forName(className);
        System.out.println("aClass = " + aClass);
    }
}

(2)获取空参构造_public

1.Class类中的方法:
  Constructor<T> getConstructor(Class<?>... parameterTypes)->获取指定的public的构造
                                parameterTypes:可变参数,可以传递0或多个参数
 
  a.如果获取的是空参构造:参数不用写
  b.如果获取的是有参构造:参数写参数类型的class对象
      
2.Constructor类中的方法:
  T newInstance(Object... initargs)  -> 创建对象
               initargs:传递的是构造方法的实参
                
  a.如果根据空参构造new对象,initargs不写了
  b.如果根据有参构造new对象,initargs传递实参

public class Test03_GetConstructor {
    public static void main(String[] args) throws Exception {
        Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getConstructor();
        System.out.println("constructor = " + constructor);
        /*
          好比是: Person person = new Person();
         */
        Person person = constructor.newInstance();

        //好比是:直接输出对象名,默认调用toString
        System.out.println(person);
    }
}

 (3)利用空参构造创建对象的快捷方式_public

Class类中的方法:
  T newInstance()   ->  根据空参构造new对象
      
前提:被反射的类中必须有public的空参构造  

public class Test04_GetConstructor {
    public static void main(String[] args) throws Exception {
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        System.out.println(person);
    }
}

(4)利用反射获取有参构造并创建对象_public

1.Class类中的方法:
  Constructor<T> getConstructor(Class<?>... parameterTypes)->获取指定的public的构造
                                parameterTypes:可变参数,可以传递0或多个参数
 
  a.如果获取的是空参构造:参数不用写
  b.如果获取的是有参构造:参数写参数类型的class对象
      
2.Constructor类中的方法:
  T newInstance(Object... initargs)  -> 创建对象
               initargs:传递的是构造方法的实参
                
  a.如果根据空参构造new对象,initargs不写了
  b.如果根据有参构造new对象,initargs传递实参

public class Test05_GetConstructor {
    public static void main(String[] args) throws Exception {
        Class<Person> class1 = Person.class;
        Constructor<Person> constructor = class1.getConstructor(String.class, Integer.class);
        System.out.println("constructor = " + constructor);

        /*
           好比是:Person person = new Person("柳岩",36);
         */
        Person person = constructor.newInstance("柳岩", 36);

        //好比是直接输出Person对象,默认调用toString
        System.out.println(person);
    }
}

(5)利用反射获取私有构造(暴力反射)

1.Constructor<?>[] getDeclaredConstructors()  -> 获取所有构造方法,包括private和public
2.Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) -> 获取指定构造,包括private和public
               parameterTypes:参数类型的class对象
                   
                   
3.Constructor有一个父类叫做AccessibleObject,里面有一个方法:
  void setAccessible(boolean flag) -> 修改访问权限
                     flag为true-> 解除私有权限

public class Test06_GetConstructor {
    public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
    }
}
public class Test07_GetConstructor {
    public static void main(String[] args)throws Exception {
        Class<Person> personClass = Person.class;
        Constructor<Person> ds = personClass.getDeclaredConstructor(String.class);

        //解除私有权限 -> 暴力反射
        ds.setAccessible(true);

        Person person = ds.newInstance("曼曼");
        System.out.println(person);
    }
}

4)反射方法

(1)利用反射获取所有成员方法_public

1.Class类中的方法:
  Method[] getMethods() -> 获取所有的public的方法,包括父类中的public方法

public class Test08_GetMethod {
    public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

(2)反射之获取方法(有参,无参)

1.Class类中的方法:
  Method getMethod(String name, Class<?>... parameterTypes)->获取指定的public的成员方法
                   name:传递方法名
                   parameterTypes:方法参数类型的class对象
                       
2.Method中的方法:
  Object invoke(Object obj, Object... args)  -> 执行方法
                obj:根据构造new出来的对象
                args:方法实参
                    
                返回值:Object -> 接收被执行方法的返回值的,如果方法没有返回值,不用接收了   

public class Test09_GetMethod {
    public static void main(String[] args)throws Exception {
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        Method setName = personClass.getMethod("setName", String.class);

        /*
          相当于:person.setName("柳岩")
         */
        setName.invoke(person,"柳岩");
        System.out.println(person);

        System.out.println("================================================");

        Method getName = personClass.getMethod("getName");

        //好比是:Object o = person.getName()
        Object o = getName.invoke(person);
        System.out.println("o = " + o);
    }
}

反射小练习

<select id="findAll" class="类的全限定名">
     select * from 表名
</select>

public List<泛型类型> findAll();

 需求:在配置文件中,配置类的全限定名,以及方法名,通过解析配置文件,让配置好的方法执行起来
     className=com.atguigu.d_reflect.Person
     methodName=eat
    
步骤:
  1.创建properties配置文件,配置信息
    a.问题:properties配置文件放到哪里?
          将来我们开发完之后我们给用户的是out路径下的class文件,如果将配置文件直接放到模块下,那么out路径下是不会生成配置文件的,如果没有配置文件,程序也运行不起来
          所以我们将配置文件可以放到src下,放到src下,out路径下就会自动生成配置文件
        
    b.问题:将配置文件放到src下,out路径下会自动生成该配置文件,但是如果我们将所有的配置文件都放到src下,那么src会显得非常乱
          所以我们可以单独去创建一个文件夹,将所有配置文件放到此文件夹下,将此文件夹改成资源目录resources
         
  2.读取配置文件,解析配置文件
    a.问题:如果将配置文件放到resources资源目录下,我们怎么读取
      new FileInputStream("模块名\\resources\\properties文件名")-> 这样不行,out下没有resources
        
    b.问题解决:用类加载器
      ClassLoader classLoader = 当前类.class.getClassLoader()
      InputStream in = classLoader.getResourceAsStream("文件名称"); //自动扫描resource下的文件(可以简单理解为扫描out路径下的配置文件)     
          
  3.根据解析出来的className创建class对象
  4.根据解析出来的methodName,获取对应的方法
  5.执行方法

className=com.atguigu.d_reflect.Person
methodName=eat

 

public class Test01 {
    public static void main(String[] args)throws Exception {
        //1.创建Properties集合
        Properties properties = new Properties();
        //2.读取配置文件
        InputStream in = Test01.class.getClassLoader().getResourceAsStream("pro.properties");
        //3.将流中的数据加载到集合中
        properties.load(in);
        //4.获取读取到的配置文件中的信息
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        //5.根据className获取class对象
        Class<?> aClass = Class.forName(className);
        Object o = aClass.newInstance();
        //6.根据methodName获取方法
        Method method = aClass.getMethod(methodName);
        //7.执行被反射出来的方法
        method.invoke(o);
    }
}

第四部分、注解

1)注解的基本介绍

1.引用数据类型:
  类 数组 接口 枚举 注解
      
1.jdk1.5版本的新特性->一个引用数据类型
       和类,接口,枚举是同一个层次的
     
       引用数据类型:类 数组  接口 枚举 注解
2.作用:
        说明:对代码进行说明,生成doc文档(API文档)
        检查:检查代码是否符合条件   @Override(会用) @FunctionalInterface
        分析:对代码进行分析,起到了代替配置文件的作用(会用)
3.JDK中的注解:
        @Override  ->  检测此方法是否为重写方法
           jdk1.5版本,支持父类的方法重写
           jdk1.6版本,支持接口的方法重写
        @Deprecated -> 方法已经过时,不推荐使用
                       调用方法的时候,方法上会有横线,但是能用
        @SuppressWarnings->消除警告  @SuppressWarnings("all")     

public class Person {
    @Deprecated
    public void eat(){
        System.out.println("人要干饭");
    }
}
@SuppressWarnings("all")
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.eat();

        System.out.println("=================");

        ArrayList list = new ArrayList();
        list.add("1");
    }
}

2)注解的定义以及属性的定义格式

1.定义:
  public @interface 注解名{
      
  }

2.定义属性:增强注解的作用
  数据类型 属性名() -> 此属性没有默认值,需要在使用注解的时候为其赋值
  数据类型 属性名() default 值 -> 此属性有默认值,如果有需要,也可以二次赋值
 
3.注解中能定义什么类型的属性呢?
  a.8种基本类型
  b.String类型,class类型,枚举类型,注解类型  
  c.以上类型的一维数组   

public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}

 3)注解的使用(重点)

1.注解的使用:
  说白了就是为注解中的属性赋值
2.使用位置上:
  在类上使用,方法上使用,成员变量上使用,局部变量上使用,参数位置使用等
3.使用格式:
  a.@注解名(属性名 = 值,属性名 = 值...)
  b.如果属性中有数组:
    @注解名(属性名 = {元素1,元素2})

public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}
@Book(bookName = "金瓶梅",author = {"涛哥","金莲"},price = 9.9,count = 200)
public class BookShelf {
    
}
注解注意事项:
      1.空注解可以直接使用->空注解就是注解中没有任何的属性
      2.不同的位置可以使用一样的注解,但是同样的位置不能使用一样的注解
      3.使用注解时,如果此注解中有属性,注解中的属性一定要赋值,如果有多个属性,用,隔开
        如果注解中的属性有数组,使用{}
      4.如果注解中的属性值有默认值,那么我们不必要写,也不用重新赋值,反之必须写上
      5.如果注解中只有一个属性,并且属性名叫value,那么使用注解的时候,属性名不用写,直接写值
        (包括单个类型,还包括数组)

4)注解解析的方法->AnnotatedElement接口

1.注解解析涉及的接口:
  AnnotatedElement接口:
   实现类:AccessibleObject, Class, Constructor, Field, Method
       
2.解析思路:  先判断指定位置上有没有使用指定的注解,如果有,获取指定的注解,获取注解中的属性值
  a.boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)->判断指定位置上有没有指定的注解
    
    比如:判断BookShelf上有没有Book注解
        Class bookShelf = BookShelf.class
        bookShelf.isAnnotationPresent(Book.class)  
            
  b.getAnnotation(Class<T> annotationClass)-> 获取指定的注解
    比如:获取BookShelf上的Book注解
        Class bookShelf = BookShelf.class
        boolean result = bookShelf.isAnnotationPresent(Book.class)
        Book book = bookShelf.getAnnotation(Book.class) 

public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}
@Book(bookName = "金瓶梅", author = {"涛哥", "金莲"}, price = 9.9, count = 200)
public class BookShelf {
}
public class Test01 {
    public static void main(String[] args) {
        Class<BookShelf> bookShelfClass = BookShelf.class;
        boolean b = bookShelfClass.isAnnotationPresent(Book.class);
        //System.out.println(b);
        if (b){
            Book book = bookShelfClass.getAnnotation(Book.class);
            System.out.println(book.bookName());
            System.out.println(Arrays.toString(book.author()));
            System.out.println(book.price());
            System.out.println(book.count());
        }
    }
}

以上代码没解析出来:

涛哥猜想:如果Book注解被加载到内存中了,那么我们一定是能判断出来BookShelf上有没有Book注解的,但是现在没有判断出来,但是 BookShelf上确实用了Book注解了,所以涛哥猜想,Book注解有可能就没有在内存中出现

第五部分、元注解

1.概述:元注解是管理注解的注解
2.从哪些方面管理呢?
  a.控制自定义注解的使用位置
    控制自定义注解是否能在类中使用
    控制自定义注解是否能在方法上使用
    控制自定义注解是否能在成员变量上使用等
    
  b.控制自定义注解的生命周期(加载位置):
    控制自定义注解是否能在源码中出现
    控制自定义注解是否能在class文件中出现
    控制自定义注解是否能在内存中出现
        
3.怎么使用:
  a.@Target:控制自定义注解的使用位置
            属性:ElementType[] value();
                ElementType是一个枚举,里面的枚举类型可以类名直接调用
            ElementType中的枚举:
                TYPE:控制注解能使用在类上
                FIELD:控制注解能使用在属性上
                METHOD:控制注解能使用在方法上
                PARAMETER:控制注解能使用在参数上
                CONSTRUCTOR:控制注解能使用在构造上
                LOCAL_VARIABLE:控制注解能使用在局部变量上    
                    
  b.@Retention:控制自定义注解的生命周期(加载位置)
               属性:RetentionPolicy value()
                   RetentionPolicy是一个枚举类,里面的枚举可以类名直接调用
               RetentionPolicy中的枚举:
                   SOURCE:控制注解能在源码中出现  -> 默认
                   CLASS:控制注解能在class文件中出现    
                   RUNTIME:控制注解能在内存中出现   

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}

注解再次解析(成功了)

public class Test01 {
    public static void main(String[] args) {
        Class<BookShelf> bookShelfClass = BookShelf.class;
        boolean b = bookShelfClass.isAnnotationPresent(Book.class);
        //System.out.println(b);
        if (b){
            Book book = bookShelfClass.getAnnotation(Book.class);
            System.out.println(book.bookName());
            System.out.println(Arrays.toString(book.author()));
            System.out.println(book.price());
            System.out.println(book.count());
        }
    }
}

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象编程是一种编程范式,它将程序的构建和设计思路以面向对象的方式进行组织和实现。在Java中,面向对象编程是基于Java SE(Standard Edition)的一种编程方式。第07讲主要介绍了面向对象编程中的一些基本概念和关键术语。 在面向对象编程中,我们将程序中的数据和对数据的操作(方法)封装在一起,形成一个对象。对象由两部分构成:属性和方法。属性是用来描述对象的特征,而方法则是对象可以执行的操作。对象之间通过消息(方法调用)进行通信和交互。面向对象的核心思想是通过封装、继承和多态实现程序的复用和扩展。 封装是面向对象编程中的一个重要概念,它指的是将类的属性和方法进行封装,使得外部无法直接访问和修改对象的内部状态,只能通过公共的方法来操作属性和执行方法。封装提供了一种将数据和行为组合在一起的方式,可以保护数据的完整性和安全性。 继承是面向对象编程中的另一个重要概念,它指的是通过定义一个新的类来继承现有类的属性和方法。通过继承,子类可以继承父类的属性和方法,并可以在此基础上进行扩展和修改。继承提供了一种代码复用的机制,可以减少重复编码的工作量。 多态是面向对象编程的又一个重要概念,它指的是同一类型的对象在不同的情况下可以有不同的表现形式。多态通过方法的重写和方法的重载实现。方法的重写指的是在子类中重新定义和实现父类的方法,方法的重载指的是在同一个类中可以定义多个同名但参数列表不同的方法。 总结来说,面向对象编程是一种将程序组织和设计思路以对象为中心的编程方式。在JavaSE中,我们可以通过封装、继承和多态来实现面向对象编程的目标。封装可以提高程序的可维护性和可复用性,继承可以减少重复编码的工作量,多态可以灵活地操作对象。掌握这些基本概念和关键术语,可以帮助我们更好地理解和应用面向对象编程的思想。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值