图书管理系统(反射,注解)与基础知识的梳理

知识梳理: 

今天是学习Java的第三周,也差不多将Java SE的基础学习完了,这次的内容更多是梳理与整合,并将学习的内容应用到一个小项目里。

这次我做的是一个图书管理系统,最后我再通过项目来更加详细的说明我的思路

下面是我对Java基础的理解和整理(仅是本人的理解,没那么详细):

一:Java的基础语法与数据类型

Java的基础语法:if判断语句,case(我不是很喜欢用),for循环,增强for循环

数据结构:数据结构分为基本数据类型引用数据类型

基本数据类型:byte,short,int,long,float,double,char,boolean

引用数据类型:String(重要)除了基本数据类型,其他都是引用数据类型。Object是所有引用数据类型的根基。所有引用数据类型都继承了Object

二:面向对象的基本语法和关键字

java是一个强面向对象的语言,我这里就不去解释什么是面向对象了,简单梳理一下面向对象的语法内容和关键字

修饰符我就只说几个了

public:表示可以在任何类中调用

private:私有访问,只对同一个类可见,其余都无法访问(提供get,set方法)

static :静态的,无需创建实例,通过类名访问

下面是一些关键字:

this:指向当前实例对象的内存地址(这里我就不画图了),也就是当前对象

super:指向的是父类的东西,这块大家多写就可以理解了或者是看看别的大佬的详解,下面是我觉得写的很好的文章

java语言之super关键字详解_super java-CSDN博客

然后是构造函数,构造代码块,静态代码块

 我先说一下Java的执行顺序,当一个代码写完后,这时编译阶段,然后Java会将代码编写成.class文件,Java虚拟机获取.class文件进行加载,加载成功后进行初始化,最后运行,简单一点就是:

编译  ---->  生成.class文件  ---->   加载   ----->   初始化   ---->  运行

静态代码块:在.class文件加载时运行,为静态变量赋值,最先执行

构造代码块:每次在创建一个对象的时候,就会执行此区域的代码

构造函数:初始化对象

所以执行顺序应该是:静态代码块--->构造代码块--->构造函数

new关键字:它的作用是在堆中开辟出一个空间,存放实例化的对象

不是很重要,当作一个理解:new对象也就是开辟出一块空间,这时是为所有的对象属性附上默认值,只有执行了构造函数才会为所有对象的属性附上对应的值

三:多态,继承,接口,抽象类

个人觉得这里是我最喜欢Java的地方应该也是精髓,我以前是学习过python的,虽然python也是面向对象,可能是我没有深入,觉得python这块是不如Java更体现面向对象的(我很喜欢python)

继承:

关键字:extends 父类

继承我觉得应该是很好理解的部分

比如我们创建了一个,人,这个类,属性有,名字,年龄,性别等信息

现在我又创建一个类,男孩,这个类也有名字,年龄,性别,但是还有更丰富的信息,爱好

这时候我们发现人这个类的属性,男孩也有,所以造成了代码复用,我们让男孩继承人,本质上就是获取了人这个类的所有属性和方法,我们不需要再重写了。

简单说一下,大家多写一点代码,看看别的大佬的讲解

多态

本质:父类型指向子类型对象

我这里不再去多说多态,抽象类,接口的内容了,哈哈哈偷懒了,因为之前写了太多次了

抽象类与接口的结合使用(英雄打怪兽)-CSDN博客

大家如果不嫌弃可以去看看我写的这个,里面有多态的体现,并且还有抽象类与接口的理解

 四:toString,equals

这两个方法是很常用很重要的,都是Object的方法,由于所有类都继承了Object,所以每个类都有这些方法

首先来说一下toString:当我们打印一个对象的时候,输出,其实是调用的该对象的toString方法,而老祖宗Object的toString方法打印的是该对象的内存地址,所以我们要重写toString方法,来改变我们要输出的内容,可能是姓名+年龄了等等等,按照你的需求来重写

equals:这是一个比较方法,Object的equals方法,比较的是两个对象的内存地址,相同返回true,不相同返回false,可是我们的目标假如是,两个人的名字相同,我们就认为他俩相等,是一人,如果我们不重写equals方法,返回的是false,因为new了两次,这是两个不同的内存地址,所以我们要重写,并实现我们想要的判断

IDEA有快捷键,ALT+INSERT,本人很懒哈哈哈,它会帮我们生成,大家选对应属性就好

五:数组

学生管理系统(数组的理解)-CSDN博客

哈哈哈哈又是我写的,大家不嫌弃可以去看看,偷懒了偷懒了,因为后面的集合,要比数组灵活的多得多,知道了集合,我就没用过数组了,操作性很低。

六:String与StringBuilder

String是字符串,是一种引用数据类型,在Java中,凡是用双引号括起来的,都是String类型的数据,java中规定,双引号括起来的字符串,是不可变的,也就是说"abc"自出生到最终死亡,不可变,不能变成"abcd",也不能变成"ab" ,我们看到对字符串修改,其实在底层是调用StringBuilder进行了修改,然后执行了StringBuilder的toString方法变成了字符串。

字符串常量池: 在Java中,编译阶段会将所有的字符串,存放到方法区的字符串常量池中

Java中 String类的详解(非常全面细致)_java中string-CSDN博客

java String类(超详细!)_java string类型-CSDN博客

上面这个博客讲述了String类的常用方法,方法太多了,我一般也是用什么去搜什么,多搜多写也就记住一些了,还有字符串常量池的理解,和一些字符串相关的练习题

StringBuilder:可变长度的字符串

字符串是不可变的,但是StringBuilder是可以更改字符串长度的,所以StringBuilder常用于字符串的拼接

七:集合

java集合(超详细)-CSDN博客

很详细的集合讲解 

集合就是在内存中申请一块空间用来存储数据,在Java中集合就是替换掉定长的数组的一种引用数据类型

集合只能装载同一种数据类型,数组可以装载不同的数据类型

集合可变,数组不可变

我这里就说两个常见的集合:HashMap,Arrlist

HashMap:以键值对的形式存储数据

Arrlist:底层是数组,可变,是动态的,所以查询效率高,增删效率低

八:Comparable、Comparator

这是两个实现比较的接口

Java比较器-Comparable_java comparable-CSDN博客

Comparable:在自定义类中实现此接口,并重写compareTo方法

这种方法可扩展性低,如果确定了此类的比较固定不变,建议写在类中

Comparator:传入比较器,比较器实现Comparator接口

这种方法可扩展性高,如果觉得此类的比较可能发生改变,建议用传比较器的方式

 九:IO流

目前用的少,这块的东西很多,大多数都是需要记忆的,更重要的是理解包装,装饰器的设计模式

IO流与装饰器设计模式的理解-CSDN博客

我写的相关博客内容 

【Java基础-3】吃透Java IO:字节流、字符流、缓冲流_缓冲流是字节流吗-CSDN博客

大佬的博客,看完一定有新的理解 ,很喜欢的一个大佬

十:反射与注解

这是我最近新学的内容,我来说一下我对反射和注解的一些理解

对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象

我们该怎么通俗的理解呢,首先我们要知道,Java其实是获取.class文件来运行与加载的,也就是我们获取了对应类的.class文件,我们就可以获取它的属性与方法,这种行为就是反射

让我们再梳理一下Java的内部结构和一个对象的创建过程

我们在学习反射前创建一个对象是用new,在堆中开出一个空间,然后引用指向这个空间,去获取这个对象的信息

而反射我觉得是反正来的,看下面的图,我们发现是由一个class对象生成了两个对象,然后再去将堆中对象的内存地址分配到引用上

我刚开始学习的时候我也很疑惑,反射这有什么用,我为什么不直接new一个对象,

获取class对象再去new对象,这不是多此一举吗,后面我自己写代码的时候搞懂了,反射要干什么了,我来举一个例子,假如我们定义了好多好多的类,你获取到了一个已经不知道是什么的对象,我们需要获取该对象的属性,假如是名字,而该类并没有提供get方法,我们该怎么办

或者说,我们需要获取学生的所有属性和对应的属性值,我们难道要一个一个使用get方法吗,假设我们获取到了所有属性和对应属性值,这时候如果传入的是一个老师,我们是不是还要重新再来一次,可扩展性很小

而使用反射后,我们可以接收任意一个对象,我们只需要知道该对象的.class文件,就可以获得该对象的所有内容,包括其对应的注解

我这里先不上代码,可以先理解一下,下面结合代码可能就更好理解了

Java 中的反射机制(两万字超全详解)_java反射-CSDN博客

反射的方法很多,我就不去写了,请看大佬的整合,忘记该怎么用就查一下

我下面再来说一下注解的理解

什么是注解,其实我们一直在使用,在重写方法的时候,我们会看到@Override

等等的相关@内容,这就是注解

我刚开始,有点懵,我不知道这个注解有什么用,这不是多此一举吗,哈哈哈和反射学习的时候是一样的,也觉得作用不大,可是我在写代码的时候发现,注解是很重要的,它和反射是天生一对。

注解是干什么的呢,我们先知道注释是什么,注释是给我们人看的,对代码的解释

而注解是给程序看的,是解释给程序看的

我们可以这样理解,我们写了一大堆的类,有一个类是冰箱,而其他类都是动物,现在我有一个需求,请找到电器相关的类,我们该怎么办

所以这时候注解的作用就来了,我们为冰箱类打上一个标签,电器,程序看到了这个标签,知道了你是电器,就会输出你,没有电器标签的我全部忽略,这里的标签,就是注解

我们代入到现实生活中,我们提到蔡徐坤,第一时间想到的是什么,是鸡,那么鸡就是蔡徐坤的标签,我们提到富豪,想到的是比尔盖茨,那么我们就是为比尔盖茨贴上了富豪的标签

再具体一点就是将一个事物进行抽象的解释。

当理解了什么是注解,请看下面这个博客哈哈哈,具体方法调用我就不去讲了

Java基本注解详解(超级详细)_java常用注解-CSDN博客

图书管理系统:

下面就是我本次实现的一个图书管理系统了,下面是我的实现图:

本次的目标就是通过管理员对电影数据进行增删改查,用户进行观看电影并进行评价,更改电影的评论和电影的评分,并对打上标签的信息进行数据库建表(数据库还不会连接使用哈哈哈我就简单写逻辑和语句,并打印出来,就当插入了)

这是本次的所有类,看起来很多其实不是特别难,主要是理解反射与注解

大家如果需要可以和我这样建包放入代码,还有很多小细节我没有去实现,主体内容已经完成了

我下面开始说一下这个代码

UserInformation类:
package information;

import annotation.Column;
import annotation.Table;

@Table("user_table")
public class UserInformation {
    @Column(name = "user_id",type = "int")
    private int id;
    @Column(name = "user_name")
    private String name;
    @Column(name = "user_password")
    private String password;
    @Column(name = "user_email")
    private String email;

    private Userrecord userrecord;

    public UserInformation() {
    }

    @Override
    public String toString() {
        return "information.UserInformation{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", userrecord=" + userrecord +
                '}';
    }

    public UserInformation(int id, String name, String password, String email) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.email = email;
    }

    public Userrecord getUserrecord() {
        return userrecord;
    }

    public void setUserrecord(Userrecord userrecord) {
        this.userrecord = userrecord;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

 如果看不懂注解,我们先忽略,其他的就是一个普通类的构建,我就不多说了

FilmInformation类:
package information;

import annotation.Column;
import annotation.Table;
import annotation.creatTable;

import java.lang.reflect.Constructor;

@Table("file_table")
public class FilmInformation {
    @Column(name = "file_name")
    private String film_name;
    @Column(name = "score",type = "int")
    private int score;
    // 用户:评论
    private final Filmrecord comment = new Filmrecord();

    public FilmInformation() {
    }

    public FilmInformation(String film_name, int score) {
        this.film_name = film_name;
        this.score = score;
    }

    public String getfilm_name() {
        return film_name;
    }

    public void setFilm_name(String film_name) {
        this.film_name = film_name;
    }

    public int getscore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }


    @Override
    public String toString() {
        return "FilmInformation{" +
                "film_name='" + film_name + '\'' +
                ", score=" + score +
                ", comment=" + comment +
                '}';
    }
    public void addComment(String user_name,String comment,FilmInformation filmInformation){
        this.comment.addComment(user_name,comment);
        try {
            Class<?> fileCord = Class.forName("information.Filmrecord");
            Constructor<?> constructor = fileCord.getConstructor(user_name.getClass(), comment.getClass());
            Object o = constructor.newInstance(user_name, comment);
            //插入评论信息到电影评论表中
            creatTable.start(o);
            //修改电影信息的评分,未实现
            creatTable.set(filmInformation);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

还是一样的,不懂先忽略注解与反射,这就是一个电影信息类的构建

Filmrecord类:
package information;

import annotation.Column;
import annotation.Table;

import java.util.HashMap;
import java.util.Map;
@Table("file_record")
public class Filmrecord {
    @Column(name = "userName")
    String userName;
    @Column(name = "file_comment")
    String file_comment;

    private Map<String,String> comment = new HashMap<>();

    public Filmrecord() {
    }

    public Filmrecord(String userName, String file_comment) {
        this.userName = userName;
        this.file_comment = file_comment;
    }

    public void addComment(String user_name, String comment){
        this.comment.put(user_name, comment);
    }

    @Override
    public String toString() {
        return "Filmrecord{" +
                "comment=" + comment +
                '}';
    }

    public Map<String, String> getComment() {
        return comment;
    }

    public void setComment(Map<String, String> comment) {
        this.comment = comment;
    }

}
Userrecord类:
package information;

import annotation.Column;
import annotation.Table;

@Table("user_record")
public class Userrecord {
    @Column(name = "record_filmname")
    private String filmName;
    @Column(name = "record_elapsedTime")
    private long elapsedTime;
    @Column(name = "record_comment")
    private String comment;

    public Userrecord() {
    }

    public String getFilmName() {
        return filmName;
    }

    @Override
    public String toString() {
        return "电影名字:" + filmName +
                ", 观看时长:" + elapsedTime + "秒" +
                ", 发表评论:" + comment;
    }

    public void setFilmName(String filmName) {
        this.filmName = filmName;
    }

    public Userrecord(String filmName, long elapsedTime, String comment) {
        this.filmName = filmName;
        this.elapsedTime = elapsedTime;
        this.comment = comment;
    }

    public Userrecord(int id, String name, String password, String email, String filmName, long elapsedTime, String comment) {
        this.filmName = filmName;
        this.elapsedTime = elapsedTime;
        this.comment = comment;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public long getElapsedTime() {
        return elapsedTime;
    }

    public void setElapsedTime(long elapsedTime) {
        this.elapsedTime = elapsedTime;
    }
}

这四个类没什么可说的,全都是基本的构建,我们先把地基搞起来,下面我们要构造存放这些信息的两个库,实际上就是两个集合

FilmBase类:
package base;

import information.FilmInformation;

import java.util.Collection;
import java.util.HashSet;

public class FilmBase {
    private static Collection<FilmInformation> film =new HashSet<>();

    public static Collection<FilmInformation> getFilm() {
        return film;
    }

    public static void setFilm(Collection<FilmInformation> film) {
        FilmBase.film = film;
    }
}
UserBase类:
package base;

import information.UserInformation;

import java.util.ArrayList;
import java.util.Collection;

public class UserBase {
    private static Collection<UserInformation> user =new ArrayList<>();

    public static Collection<UserInformation> getUser() {
        return user;
    }

    public void setUser(Collection<UserInformation> user) {
        UserBase.user = user;
    }
}

我们先来分析一下,我们需要向库中加入对应信息,所以规定了对应的泛型,并且将库设置为静态,我希望通过库名直接获取对应的集合。

两个集合的类型,我将电影设置为哈希集合,因为电影是无序,且名字不能重复,不能有两个一样的电影吧,并通过键值对来体现电影与评论的关系,而评论也是一个集合,所以一个电影对应着很多信息,想象成评论区就好。

而用户我使用的是数组集合,因为用户可能有相同的,小号是吧,其实也是为了多用其他集合,都试试哈哈哈,我觉得还是一对多的方式更好,想象成我们的历史记录

UserLoginAndRegister类:
package loginAndRegister;

import annotation.creatTable;
import base.UserBase;
import information.UserInformation;

import java.util.Iterator;
import java.util.Scanner;

public class UserLoginAndRegister {
    private static final Scanner s = new Scanner(System.in);

    public UserLoginAndRegister() {
    }

    public static void login() {
        System.out.print("请输入你的账号:");
        int id = s.nextInt();
        System.out.print("请输入你的密码:");
        String password = s.next();

        Iterator<UserInformation> it = UserBase.getUser().iterator();
        boolean userFound = false; // 标记是否找到用户

        while (it.hasNext()) {
            UserInformation user = it.next();

            if (id == user.getId()) {
                userFound = true; // 找到了用户
                if (password.equals(user.getPassword())) {
                    System.out.println("登录成功");
                    SystemConstants.USERID = user.getId();
                } else {
                    System.out.println("密码错误");
                }
                break; // 已经找到用户,退出循环
            }
        }
        if (!userFound) {
            System.out.println("未找到该用户");
        }
    }

    public static void register() {
        System.out.print("请输入你的新账号:");
        int id = s.nextInt();
        System.out.print("请输入你的名字:");
        String name = s.next();
        System.out.print("请输入你的密码:");
        String password = s.next();
        System.out.print("请输入你的邮箱:");
        String email = s.next();
        UserInformation userInformation = new UserInformation(id,name,password,email);
        UserBase.getUser().add(userInformation);
        try {
            creatTable.start(userInformation);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
SystemConstants类:
package loginAndRegister;

public class SystemConstants {
    public static int USERID = 0;
}

到这我们来理一下我实现登录与注册的逻辑,首先通过键盘输入获取对应的登录信息,先判断有没有这个用户,有的话再进行密码判断,因为集合的遍历我使用的是迭代器形式,所以证明迭代器如果找到了这个用户,那么it迭代器存放的一定是该用户的相关信息,然后去进行判断就好

SystemConstants我使用了一个静态变量记录当前是哪个用户在进行登录,因为后面需要实现对该用户的信息操作。

注册没什么好讲的了,注册就是new一个对象添加到集合中。

Root类:
package root;

import annotation.creatTable;
import base.FilmBase;
import base.UserBase;
import information.FilmInformation;
import information.UserInformation;

import java.util.Iterator;
import java.util.Scanner;

public class Root implements RootAction{
    Scanner s = new Scanner(System.in);
    @Override
    public void add() {

        System.out.print("请输入电影名字:");
        String name = s.next();
        System.out.print("请输入电影评分:");
        int score = s.nextInt();
        FilmInformation film = new FilmInformation(name,score);
        FilmBase.getFilm().add(film);
        try {
            creatTable.start(film);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
    @Override
    public void delect() {
        System.out.print("请输入删除电影的名字:");
        String name = s.next();
        Iterator<FilmInformation> it = FilmBase.getFilm().iterator();
        boolean found = false;
        while (it.hasNext()) {

            FilmInformation film = it.next();

            if (name.equals(film.getfilm_name())) {
                it.remove();
                found = true;
                System.out.println("删除成功");
                break;
            }
        }
        if (!found) {
            System.out.println("未找到该电影");
        }
    }
    @Override
    public void displayuser() {
        for (UserInformation user : UserBase.getUser()) {
            System.out.println(user);
        }
    }
    @Override
    public void displayfilm() {
        for (FilmInformation film : FilmBase.getFilm()) {
            System.out.println(film);
        }
    }
}
RootAction接口:
package root;

public interface RootAction {
    void add() throws ClassNotFoundException;
    void delect();
    void displayuser();
    void displayfilm();
}

这里我也不太想详细说了,和刚刚的user是一样的,只不过变成了对电影信息进行增删改查,大家稍微看一下就明白了

AbstractMovieFramework抽象类:
package userAction;

import information.FilmInformation;

import java.util.Scanner;

public abstract class AbstractMovieFramework implements MovieFramework{
    Scanner s = new Scanner(System.in);
    protected abstract void recordWatch(FilmInformation film);
    protected abstract void searchMovie(FilmInformation film,long elapsedTime,String comment);
    public abstract void watchMovie();
}
MovieFramework接口:
package userAction;

public interface MovieFramework {
    void watchMovie();
}
 SimpleMovieFramework类:
package userAction;

import annotation.creatTable;
import base.FilmBase;
import base.UserBase;
import information.FilmInformation;
import information.UserInformation;
import information.Userrecord;
import loginAndRegister.SystemConstants;

import java.util.Iterator;
import java.util.Scanner;

public class SimpleMovieFramework extends AbstractMovieFramework{

    @Override
    // 实现搜索电影的逻辑
    public void watchMovie() {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入电影的名字:");
        String name = scanner.next();

        boolean found = false;

        for (FilmInformation film : FilmBase.getFilm()) {
            //获取用户观看的电影名字
            String filmName = film.getfilm_name();
            if (name.equals(filmName)) {
                //如果有则进入观看电影
                recordWatch(film);
                found = true;
                break;
            }
        }
        if (!found) {
            System.out.println("未找到该电影");
        }
    }

    @Override
    // 实现观看电影的逻辑
    protected void recordWatch(FilmInformation film) {
        System.out.println("成功搜索到该电影:" + film.getfilm_name());
        System.out.print("是否观看:  1:观看    2“退出" );
        int watch= s.nextInt();

        if (watch == 1){

            long startTime = System.currentTimeMillis();
            System.out.println("正在观看");
            System.out.println("输入 1 可退出观看");
            int num= s.nextInt();

            if (num == 1){
                long endTime = System.currentTimeMillis();

                long elapsedTimeMillis = endTime - startTime;
                long elapsedTime = elapsedTimeMillis / 1000;

                System.out.println("观看时间:" + elapsedTime + " 秒");
                System.out.println("请输入观影评论:");
                String comment= s.next();
                //更新用户与电影数据,实现记录观看信息
                searchMovie(film,elapsedTime,comment);
                System.out.println("已评论成功");
            }
        }
    }

    @Override
    // 实现记录观看信息的逻辑
    protected void searchMovie(FilmInformation film,long elapsedTime,String comment) {
        Iterator<UserInformation> it_user = UserBase.getUser().iterator();
        //获取集合的用户个数
        int user_length = UserBase.getUser().size();

        for (int i = 0; i < user_length; i++) {
            //拿到每次遍历到的用户,去和系统记录的常量比较,查看是否是当前登录用户
            UserInformation user = it_user.next();

            if (SystemConstants.USERID == user.getId()){
                //生成用户评论类
                Userrecord userrecord = new Userrecord(film.getfilm_name(),elapsedTime,comment);
                try {
                    creatTable.start(userrecord);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //更改用户评论属性
                user.setUserrecord(userrecord);
                //更改电影评论属性
                film.addComment(user.getName(),comment,film);
            }
        }
    }
}

主要看一下实现类,我将整个观看电影分为了三个步骤

首先查看有没有这个电影,在电影集合中遍历,没找到则提示,找到了则进入观看这个方法

观看方法中同样是对用户的输入进行判断,如果选择继续观看,先记录一下确认观看的时间,然后记录结束观看的时间,得到观看时长,然后再获取输入的评论,将该电影对象,观看时长,和评论当作参数传入到记录修改这个方法里

记录修改的方法中我们遍历用户集合,找到当前登录的用户(因为我们已经记录了登录用户),然后就是new对象,new用户评论的信息,然后调用set方法将该对象添加到用户信息中

下面就使用反射的内容了,我们可以看到我们将用户的名字,和其评论的信息,还有当前电影对象作为参数传入,我们跟踪一下:

先说明一下,这里是可以直接获取参数然后直接new一个电影评论信息对象的,可是为了熟悉反射,我这里就使用反射new对象了,首先是调用了电影评论的addComment方法,将用户姓名和信息传入,然后通过全限定类名获取到电影评论的class文件(看不懂大家去看看反射基础语法),然后获取到该class文件的构造函数,然后new了一个对象,将该电影评论对象传入到creatTable的start方法中,也就是建表和插入语句的实现类中。

Column注解:
package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    //字段的名字
    String name();
    //字段的数据类型
    String type() default "varchar";
}
Table注解:
package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    //表的名字
    String value();
}
creatTable实现类:
package annotation;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;

public class creatTable {

    private static String tableName;
    private static final StringBuilder stringBuilder = new StringBuilder();
    private static final StringBuilder stringBuilder_two = new StringBuilder();
    private static final Collection<String> table =new ArrayList<>();


    public static void start(Object object) throws Exception {

        stringBuilder.setLength(0);
        stringBuilder_two.setLength(0);

        generateCreateStatement(object);
        insert(object);

    }


    //生成建表语句
    private static void generateCreateStatement(Object object) throws Exception {

        Class<?> clazz = object.getClass();

        if (clazz.isAnnotationPresent(Table.class)) {
            Table table = clazz.getAnnotation(Table.class);
            //获取到表名
            tableName = table.value();
            if (!creatTable.table.contains(tableName)){
                creatTable.table.add(tableName);
                //System.out.println(tableName);
                stringBuilder.append("create table ");
                stringBuilder.append(tableName);
                stringBuilder.append("(");
                //获取属性
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Column.class)) {
                        Column columnAnnotation = field.getAnnotation(Column.class);
                        String columnName = columnAnnotation.name();
                        String columnType = columnAnnotation.type();
                        stringBuilder.append(columnName).append(" ").append(columnType).append(",");
                    }
                }
                //删除最后一个逗号
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                stringBuilder.append(");\n");
            }
        }
        System.out.println(stringBuilder);
    }
    //插入语句
    private static void insert(Object object) {
        Class<?> filmClass = object.getClass();
        Field[] fields = filmClass.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            if (field.isAnnotationPresent(Column.class)){
                field.setAccessible(true);
                try {
                    stringBuilder_two.append("insert ")
                            .append(field.getName())
                            .append(" ")
                            .append(field.get(object))
                            .append(" ")
                            .append("to ")
                            .append(tableName);
                    if (i < fields.length - 1) {
                        stringBuilder_two.append("\n");
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(stringBuilder_two);
    }

    //修改语句
    public static void set(Object object){

    }
}




我觉得这里是本次项目的难点,注解的语法我就不去讲了,我们去理逻辑,首先我定义了两个注解,一个是表注解,一个是字段注解,被表注解标记的类,是需要建表的,被字段注解标记的属性,是需要进行插入的字段,也就是说我们为类和类中的属性打上了不同的标签,这时候我们再回去看四个信息类的注解,我相信能理解了,我们的目标就是让java虚拟机知道对于它来说这是什么,你遇到被表注解标记的类和被字段注解标记的属性你该做什么,这个过程还是需要我们去实现的

下面我分析一下代码

我需要在整个类中使用这四个变量,因为是两个方法,一个建表一个插入,而都需要表名,所以我将表面定义成静态变量,两个字符串拼接,而最后的集合是为了存放表信息的,如果我们建了一个表,将表添加到集合中,便于后面进行判断,这个目的是每个表只能建一次

 

 还记得我们刚刚调用start方法传入的是什么吗,是一个引用,引用指向的就是该对象的内存地址传入到建表方法中

当我们获取到对象后,我们就可以 获取该对象的.class对象,然后我们判断该类是不是被建表注解标记的,如果是的,我们获取到该类对应的表名

下面就是对该表名进行判断,如果在集合中证明已经建过了,没有则建表,下面就没什么技术含量了一个字符串的拼接

在最后获取属性这里,sql语句需要获取对应的字段名,所以这就是我开始说反射那里,我们需要动态获取.class文件的所有属性,然后判断每个属性是否被字段名注解标记,标记了则获取对应字段名,然后进行字符串拼接。

 如果上面看懂了,这里我相信大家也能理解了,我们同样获取对象的.class对象,然后我们遍历该.class对象的属性,去判断是否被字段注解标记,如果标记了,我们对其进行获取并进行字符串拼接。

Decorator类:
package userAction;

public abstract class Decorator implements MovieFramework{
    public MovieFramework movieFramework;

    public Decorator(MovieFramework movieFramework) {
        this.movieFramework = movieFramework;
    }

    @Override
    abstract public void watchMovie();
}
 ConcreteDecoratorBrush类:
package userAction;

public class ConcreteDecoratorBrush extends Decorator{
    public ConcreteDecoratorBrush(MovieFramework movieFramework) {
        super(movieFramework);
    }
    SimpleMovieFramework simpleMovieFramework = (SimpleMovieFramework) movieFramework;

    @Override
    public void watchMovie() {
        System.out.println("恭喜您登录成功,请按照提示操作");
        simpleMovieFramework.watchMovie();
        System.out.println("感谢您的观看");
    }
}

我这里就是实现了一个装饰器功能,对观看的方法进行包装,不懂可以去看一下我之前写的装饰器介绍

Text测试类:
import annotation.creatTable;
import information.UserInformation;
import loginAndRegister.UserLoginAndRegister;
import root.Root;
import userAction.AbstractMovieFramework;
import userAction.ConcreteDecoratorBrush;
import userAction.SimpleMovieFramework;

import java.util.Scanner;

public class Text {
    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        AbstractMovieFramework action = new SimpleMovieFramework();
        ConcreteDecoratorBrush concreteDecoratorBrush = new ConcreteDecoratorBrush(action);
        Root root = new Root();

        while (true){
            System.out.println("请登录:");
            System.out.println("1.用户登录:");
            System.out.println("2.用户注册:");
            System.out.println("3.管理登录:");
            int num = s.nextInt();
            if (num == 1){
                UserLoginAndRegister.login();
                concreteDecoratorBrush.watchMovie();

            }
            if (num == 2){
                UserLoginAndRegister.register();
            }
            if (num == 3){
                System.out.println("1.添加电影:");
                System.out.println("2.查看用户信息:");
                System.out.println("3.查看电影信息:");
                int num2 = s.nextInt();

                if (num2 == 1){
                    root.add();
                }
                if (num2 == 2){
                    root.displayuser();
                }
                if (num2 == 3){
                    root.displayfilm();
                }
            }
            if (num == 4){
                break;
            }
        }
    }
}

到这里就结束了,这个程序肯定是有一些细节没时间,我就不去实现了,比如说电影评分一定不是一个人评分就改一次,应该是取平均数,我设置了set方法,大家感兴趣可以去实现一下

如果有不对的地方,希望大家指出,谢谢大家的观看!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值