知识梳理:
今天是学习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 父类
继承我觉得应该是很好理解的部分
比如我们创建了一个,人,这个类,属性有,名字,年龄,性别等信息
现在我又创建一个类,男孩,这个类也有名字,年龄,性别,但是还有更丰富的信息,爱好
这时候我们发现人这个类的属性,男孩也有,所以造成了代码复用,我们让男孩继承人,本质上就是获取了人这个类的所有属性和方法,我们不需要再重写了。
简单说一下,大家多写一点代码,看看别的大佬的讲解
多态
本质:父类型指向子类型对象
我这里不再去多说多态,抽象类,接口的内容了,哈哈哈偷懒了,因为之前写了太多次了
大家如果不嫌弃可以去看看我写的这个,里面有多态的体现,并且还有抽象类与接口的理解
四:toString,equals
这两个方法是很常用很重要的,都是Object的方法,由于所有类都继承了Object,所以每个类都有这些方法
首先来说一下toString:当我们打印一个对象的时候,输出,其实是调用的该对象的toString方法,而老祖宗Object的toString方法打印的是该对象的内存地址,所以我们要重写toString方法,来改变我们要输出的内容,可能是姓名+年龄了等等等,按照你的需求来重写
equals:这是一个比较方法,Object的equals方法,比较的是两个对象的内存地址,相同返回true,不相同返回false,可是我们的目标假如是,两个人的名字相同,我们就认为他俩相等,是一人,如果我们不重写equals方法,返回的是false,因为new了两次,这是两个不同的内存地址,所以我们要重写,并实现我们想要的判断
IDEA有快捷键,ALT+INSERT,本人很懒哈哈哈,它会帮我们生成,大家选对应属性就好
五:数组
哈哈哈哈又是我写的,大家不嫌弃可以去看看,偷懒了偷懒了,因为后面的集合,要比数组灵活的多得多,知道了集合,我就没用过数组了,操作性很低。
六: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中集合就是替换掉定长的数组的一种引用数据类型
集合只能装载同一种数据类型,数组可以装载不同的数据类型
集合可变,数组不可变
我这里就说两个常见的集合:HashMap,Arrlist
HashMap:以键值对的形式存储数据
Arrlist:底层是数组,可变,是动态的,所以查询效率高,增删效率低
八:Comparable、Comparator
这是两个实现比较的接口
Java比较器-Comparable_java comparable-CSDN博客
Comparable:在自定义类中实现此接口,并重写compareTo方法
这种方法可扩展性低,如果确定了此类的比较固定不变,建议写在类中
Comparator:传入比较器,比较器实现Comparator接口
这种方法可扩展性高,如果觉得此类的比较可能发生改变,建议用传比较器的方式
九:IO流
目前用的少,这块的东西很多,大多数都是需要记忆的,更重要的是理解包装,装饰器的设计模式
我写的相关博客内容
【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方法,大家感兴趣可以去实现一下
如果有不对的地方,希望大家指出,谢谢大家的观看!