大一暑假学习记录

では、ゲームを始(はじ)めましょう

自己与研究生无缘了, 不过嘛, 是好是坏我也不知道, 现在也只能多学点技术, 去工作了, 这个暑假很重要, 所以将会每天记录下.

在线图床
设计模式主要学习
设计模式次要补充 – head first java 设计模式

总结


总结一下这个暑假都干了什么, 马上就要开学了.
七月十三日到七月十九日, 这是第一周了.这一周伴随着到处参观, 收货很少了. 那时我还在主用Java, 主要的是学习了一些设计模式, 这一周的时间对我学习C++ 帮助也是有的. 暑假学习设计模式也是出于换语言的考虑.
第一天(七月十三日)可以说是看的最多的了解了什么是耦合和解耦, 一些简单的设计模式(简单工厂, 工厂方法, 抽象工厂, 单例模式).
第二天(七月十四日) 开始初步试验大创项目的实现, 当时遇到一个BUG, 我需要返回一个东西, 但我还是需要返回后将他删除, 首先就是将他”复制了一份”, 然后删除, 却发现返回去的都是空的,了解到了Java如何进行深拷贝.
七月十六日看了下Java编程思想的多态部分, 然后主要时间修改网络助手的开机启动设置, 这样开机启动设置就没有问题了.
七月十七日收拾家伙, 休息了休息准备回家, 结果虽然我确认了好几次自己有没有带全家伙, 鼠标笔记本都带上了,
七月十八日到达北京去我姐那里暂住了, 结果发现我…..光带回了一个鼠标, 鼠标的接收器还在USB分线器上(吐血) 然后开始了一个开源项目的阅读. 云收藏(SpringBoot框架). 发现了自己没有看懂的东西(Stirng …), 就去了解下JDK从5-8每次更新加入的内容,了解到那个叫做可变参数需要搭配增强for循环使用
七月十九日-七月二十日我终于实现了自己理想….怎么说呢北方最大的漫展依然没有我想象的大, 等我有机会既定要去一次南方

七月二十一日到七月二十七日写了个后端练手(一个失物招领) . 使用了丝袜哥写Api文档, SpringJpa作为持久层? 这几天放松了玩了几天游戏可惜了.
七月二十八日总结两个小项目比较靠近项目的地方, 统一返回类型, 预定义数据, SpringJpa.
.学习了 接口 内部类 持有对象. 通过查看源码解决了一个Bug,
七月二十九日到八月二日 编写二手交易后台.

想去了解下大数据相关内容
八月三日到八月九日 看了下关于大数据的内容, 并不是很感兴趣.
八月十日到八月十五日 主要是写算法题目, 然后寻找自己是佛要从事游戏服务器编程
八月十六日到八月二十四日 上午复习高数, 下午看C++
@2019年8月24日18:21:07@

大纲

设计模式不求多, 但求会用, 极大概率调整设计模式的学习.
此外需要刷一些常用的算法

7.13-7.19
<复用类, 多态>
---六个创建型模式
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
- 单例模式
- 原型模式(略过)
- 建造者模式(略过)
7.20-7.26
<接口, 内部类, 持有对象>
---七个结构型模式
- 适配器模式
- 桥接模式
- 组合模式
- 外观模式
7.27-8.02
<类型信息, 泛型>
- 装饰模式
- 享元模式(略过)
- 代理模式
8.03-8.09
<数组, 容器深入研究>
---十一个行为型模式
- 职责链模式
- 命令模式
- 解释器模式(略过)
- 迭代器模式
- 中介者模式(略过)
- 备忘录模式(略过)
- 观察者模式
8.10-8.16
<IO, 枚举类型>
- 状态模式
- 策略模式
- 模板方法模式
- 访问者模(略过)
8.17-8.23
<注解, 并发>

では、ゲームを始(はじ)めましょう

7.13-7.19

7.13-7.19
<复用类, 多态>
---六个创建型模式
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
- 单例模式

7月13日

- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
- 单例模式

2019年7月13日12:21:17
上午参观参观参观…… 重置了下, 这个暑期表格.今天开始第一天的打卡.下午还有参观, 然后就可以开始学了

下午有b站血族直播
下午看了一个项目, 自己不会的还是太多,,,,,, 给了源码都看不太懂.
还是先继续看几个设计模式吧, 设计模式目前想的是, 了解大概, 等到时用到了再去详细学习

耦合与解耦

耦合: 两个或两个以上的体系之间互相结合, 互相影响, 产生的一个联合起来解决问题的体系.
这种体系, 不利于修改, 修改一个体系可能会影响到另一个体系, 使得另一个体系需要做出修改.
解耦: 将体系之间的联系降到最低, 各司其职, 修改本身的时候, 不需要去动其他的体系

简单工厂模式

简单工厂模式不属于GoF 23种设计模式
通过设计一个父类(产品类), 由他派生出多个子类(具体产品类), 通过一个工厂类, 提供给工厂类生产方法不同的参数, 由工厂类return相应的子类, 由父类接受.

解决问题: 通过工厂类, 只需要记住参数, 就可以产生相应的子类,
存在问题: 不符合开闭原则, 每次产生新的产品, 都需要去修改相应的工厂生产方法.

工厂方法模式

与简单工厂有些相似之处: 均存在一个产品父类和多个产品子类.
不同之处在于 工厂方法模式, 设置了工厂父类, 通过派生出不同的工厂子类来return相应的子类.

解决问题: 解决了简单工厂模式的开闭原则, 每次产生新的产品, 只需要派生一个相应的子类即可
存在问题: 系统中由于新产品的产生, 类的个数将会成对增加, 会有更多的类需要处理

抽象工厂模式

抽象工厂模式解决了工厂方法模式某些情况下 导致的类成对增加情况
一个抽象工厂里包含了这个”工厂”的所有产品–这对应了一个产品族
可以派生出多个工厂来实现多品牌产品–形成了一个等级结构
引用自上文博客

单例模式

这个模式理解起来很容易, 但是效果却十分的不错, 之前用过一次所以详细写一下.
饿汉式单例模式
饿汉式单例模式 无延迟加载 不需要解决多线程问题

/**
* @ClassName singletonpattern.Connect
* @Description
* 饿汉式单例模式 无延迟加载 不需要解决多线程问题
* Author lsmg
* Date 2019/5/21 13:25
* @Version 1.0
**/
public class Connect {
private static final Connect instance = new Connect();

private Connect(){

}

public static Connect getInstance(){
return instance;
}
}

懒汉式单例模式

package singletonpattern;
懒汉式单例模式 实现了延迟加载,但需要解决多线程问题
/**
* @ClassName singletonpattern.Connect1_2
* @Description TODO
* 懒汉式单例模式 实现了延迟加载,但需要解决多线程问题
* Author lsmg
* Date 2019/5/21 13:30
* @Version 1.0
**/
public class Connect1_2 {
private static Connect1_2 connect1_2;

private Connect1_2(){}

//这种方式会造成多线程访问的时候实例化多个对象
// public static singletonpattern.Connect1_2 getInstance(){
// if(connect1_2 == null){
// connect1_2 = new singletonpattern.Connect1_2();
// }
//
// return connect1_2;
// }

//这种方式虽然确保了只有一个线程进入, 但是降低了多线程的性能
// public synchronized static singletonpattern.Connect1_2 getInstance(){
// if(connect1_2 == null){
// connect1_2 = new singletonpattern.Connect1_2();
// }
//
// return connect1_2;
// }


//这种方式需要在private "volatile" static singletonpattern.Connect1_2 connect1_2 这样同样降低效率
// public synchronized static singletonpattern.Connect1_2 getInstance(){
// if(connect1_2 == null){
//
// synchronized (singletonpattern.Connect1_2.class){
// if(connect1_2 == null){
// connect1_2 = new singletonpattern.Connect1_2();
// }
// }
//
// }
//
// return connect1_2;
// }

使用IoDH方法结合二者优点
由于静态单例对象没有作为Singleton的成员变量直接初始化, 当调用getInstance()方法的时候, 会加载内部类HolderClass, 其中的static 由Java虚拟机保证线程安全性, 这样就结合了饿汉式单例模式的线程安全懒汉式单例模式的延迟加载

//Initialization on Demand Holder
class Singleton {
private Singleton() {
}

private static class HolderClass {
private final static Singleton instance = new Singleton();
}

public static Singleton getInstance() {
return HolderClass.instance;
}

public static void main(String args[]) {
Singleton s1, s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();
System.out.println(s1==s2);
}
}

@2019年7月13日19:07:46 设计模式暂时到这里, 去写写代码吧@

7月14日

复用类看了一部分, 目前还差final部分

@2019年7月14日09:43:46@

下午看了看大创项目的实现, 选择了高德地图api. 中午的时候太困了 搞得我没有仔细看
目前决定采用动态延展路径 解决问题, path由ajax 异步获取更新.

小插曲-Java List深浅拷贝

@Service("droneStatusService")
public class DroneStatusServiceImpl implements DroneStatusService {

private Logger logger = LoggerFactory.getLogger(DroneStatusServiceImpl.class);

private List<DroneStatus> droneStatusList = new ArrayList<>();
/**删除其他代码**/
@Override
public List<DroneStatus> listDroneStatus() {
List<DroneStatus> theDroneStatusList = droneStatusList;
droneStatusList.clear(); /**这样导致了我的return list一直为空**/
logger.info("清除一次信息list共"+theDroneStatusList.size()+"条");

return theDroneStatusList;
}
}

第一印象这样写, 排查方法就是想到了关于Java引用的部分.
对于list的拷贝 遍历循环复制List的构造方法list.addAll()以及System.arraycopy() 这些全部是浅复制他们指向了同一片内存区域

深复制的实现方法另实体类 实现Cloneable接口 重写clone方法

@Override
public Object clone() {
Entity entity = null;
try {
entity = (Entity) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return entity;
}

然后我写了一个工具类

public static List<Entity> deepCopy(List<Entity> originList) {
List<Entity> entityList = new ArrayList<>();
for(Entity entity : originList) {
entityList.add((Entity) entity.clone());
}

return entityList;
}

通过这个工具类实现深复制

IDEA CTRL+ALT+T收获这个快捷键

@2019年7月14日17:47:23@

大创先告一段落了, 等和他们对接吧, 基本功能显示路径已经做好了.
@2019年7月14日20:29:30@
复用类看完了
@2019年7月14日21:14:12@

7月15日

把GGO通关了, 游戏就告一段落了.

7月16日

多态

把编程思想-多态看一下吧

多态这里怎么说呢, 重要的是思想吧, 自己没用过太多, 都是一些框架需要
@2019年7月16日08:42:35@

把书里的内容过了一遍, 怎么感觉不是很实用. 但是也说了一些小问题. 继承这种东西, 自己代码里都没有用太多.
@2019年7月16日09:25:47@

改了一部分BUG, 小软件的开机启动设置修改了下, 貌似可以了.
@2019年7月16日17:39:40@

7月17日

上午收拾了下, 下午的话休息了休息, 晚上去吃了顿好的, 收拾回家的东西

7月18日

上午坐了一上午的车, 下午到了北京, 然后把电脑的内存条换上了(现在是16G的内存了, 够用了). 难受的是, 光带了鼠标没有带鼠标的接收器!!!!!!!(我以为插件可以代替接收器, 结果插线也得要接收器… 算了吧)

下午继续看了一部分 云收藏的源码看到了这个下面一个函数

public static void main(String[] args) {
System.out.println(getMessage("1", "2", "3", "4"));
}

public static String getMessage(String template, String... keys) {
int count = 0;
StringBuilder templateBuilder = new StringBuilder(template);
for (String key : keys) {
templateBuilder.append(key);
}
template = templateBuilder.toString();
return template;
}

重点不是函数的功能, 而是String...这不是写错了. 我去网上查了下, 这样这个函数就可以接受多个参数了
getMessage("template", "a", "b", "c") 接受参数后用 增强for循环以此取出就好

是从Java 5开始,Java语言对方法参数支持一种新写法,叫可变长度参数列表

正好在这里去搜集下每次Java更新, 所提供的新特性

JDK5 新特性

#自动装箱与拆箱

Integer a = new Integer(10); 
//这个问题不大
Integer b = 100; //这里就把一个int自动转成了 integer类型(自动装箱)
//这里用到了 Integer的 valueOf()方法 实现的自动装箱
b += 100; //b = b + 100; 用intValue()来自动拆箱
//实现方式 b = Integer.valueOf(b.intValue() + 200);

#枚举类型

switch 
// switch可以 switch枚举类型

#静态导入

import static java.lang.Math.pow; 
//静态导入的必须是静态方法
System.out.println(Math.pow(2, 3)); //未使用静态导入
System.out.println(pow(2, 3)); //使用静态导入

#可变参数

//可以在方法参数的类型中 加入三个`...`, 这样在方法体内可以使用for的增强循环来获得传入的多个参数.
public static void main(String[] args) {
System.out.println(getMessage("1", "2", "3", "4"));
}

public static String getMessage(String template, String... keys) {
int count = 0;
StringBuilder templateBuilder = new StringBuilder(template);
for (String key : keys) {
templateBuilder.append(key);
}
template = templateBuilder.toString();
return template;
}

#增强for循环
#泛型 (Generic Type)
#内省

JDK6 新特性

#Desktop类和SystemTray类
第一个Desktop
可以用来打开系统默认浏览器浏览指定的URL
打开系统默认邮件客户端给指定的邮箱发邮件
用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件)
用系统默认的打印机打印文档
第二个SystemTray
可以用来在系统托盘区创建一个托盘程序.
Java的UI方面就不写太多了

@2019年7月18日20:47:07@

Springboot配置文件

在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式
其中{profile}对应你的环境标识

下面列举三个文件
application-dev.properties:开发环境
application-test.properties:测试环境
application-prod.properties:生产环境
至于哪个具体的配置文件会被加载,需要在application.properties文件中通过spring.profiles.active属性来设置,其值对应{profile}值。
spring.profiles.active=dev

7月19日

今天的话在北京待了一天, 去看了看北方最大的漫展IDO, 怎么说呢比我想象的要小一点, 不过比徐州那个好太多了. 以后有机会的话就去南方了.

7.20-7.26

<接口, 内部类, 持有对象>
---七个结构型模式
- 适配器模式
- 桥接模式
- 组合模式
- 外观模式

7月20日

今天还是胳膊有些疼, 昨天拿的东西不少, 背的也不少.走的路也不少…..
@2019年7月20日19:39:08@

现在来看一些东西吧. 上个寒假在家里留了一本Java编程思想.

7月21日

写了个新的小项目, 正好来练练手. 新项目单独列出一篇博客.

7月22日

在家里午觉睡不着我凑, 改下小项目的问题.
@去看一下设计模式吧@

适配器模式

这个设计模式怎么说呢, 挺简单的.
就是 新建一个适配器类Adapter 引用一个需要适配的类Adaptee 这个类实现客户端的接口Target

这样客户端直接调用接口 相关转换工作在接口中完成.

7.27-8.02

<类型信息, 泛型>
- 装饰模式
- 享元模式(略过)
- 代理模式

7月28日

从7.23-7.25 写了个小项目, 失物招领的后端.
总的来说有

统一反应类型

将所有的返回结果, 写在一个类中

预先定义的异常信息, 则使用了enum

封装反回数据, 使用Object

这样处理后就可以

return new ResponseData(ExceptionMsg.DEL_FAILED);

return new ResponseData(ExceptionMsg.DEL_FAILED);

return new ResponseData(ExceptionMsg.SUCCESS, lostAndFoundInfo);

来统一返回类型

Spring Jpa的方便

配置完毕后, 去编写相应的实体类

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/lostandfound?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=update

# create:只要每次加载 Hibernate 时就都会删除上一次生成的表,然后根据 model 类再重新来生成新表.
# create-drop:每次加载 Hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。
# update:最常用的属性,第一次加载 Hibernate 时根据 model 类会自动建立起表的结构(前提是先建立# # 好数据库),以后加载 Hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
#validate :每次加载 Hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

@Entity //这里可以通过value属性指定表名, 如果不指定则为类名
public class User {

@Id
@GeneratedValue //默认情况下会创建新表来存储id位置, 如果指定 strategy= GenerationType.IDENTITY 则会在一张表中存储位置id
private Long id;
@Column(nullable = false, unique = true)
private String userName;
@Column(nullable = false)
private String passWord;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = true, unique = true)
private String nickName;
@Column(nullable = false)
private String regTime;
//省略 getter settet 方法、构造方法 在这里getter setter 影响 Controller 的 return的内容. 有get方法才会在json中含有该项, 如果不想让该项出现在json中 则不需要写对应的get方法
}

最后编写实体类对应的repository接口 继承 JpaRepository<model, Long>

就可使用自带的一些方法.

去继续学习吧

<接口, 内部类, 持有对象>

重写Readable导致的bug.
再Main方法里产生随机单词, 导致异常BufferOverflowException , 首先思考的是每次调用read()方法应该会传入一个新的CharBuffer吧(实际并不是, 后面说)

// Main.java
public static void main(String[] args) {

Scanner scanner = new Scanner(new RandomWords(100000));

while (scanner.hasNext()) {
System.out.println(scanner.next());
}
}

// RandomWords.java
public class RandomWords implements Readable {

private static Random random = new Random(100);

private static final char[] CAPITALS =
"ABCDEFGHIGKLMNOPQRSTUVWXYZ".toCharArray();

private static final char[] LOWERS =
"abcdefghigklmnopqrstuvwxyz".toCharArray();


private int count;

public RandomWords(int count) {
this.count = count;
}

@Override
public int read(CharBuffer cb) throws IOException {
if(count-- == 0) {
return -1;
}

cb.append(CAPITALS[random.nextInt(CAPITALS.length)]);

int maxCount = 4;

for (int i = 0; i < maxCount; i++) {
cb.append(LOWERS[random.nextInt(LOWERS.length)]);

//System.out.println(cb.limit() + " - " + cb.position());
cb.append(CAPITALS[random.nextInt(CAPITALS.length)]);

}

cb.append(" ");
return 10;
}
}

来到报错位置, 这一段是CharBuffer源码里的部分, 发现是由于position >= limit导致的异常, 然后查找得到这两个值得获取方法position()和limit();

final int nextPutIndex() {                          // package-private
if (position >= limit)
throw new BufferOverflowException();
return position++;
}

在RandomWords.java代码加入 System.out.println(cb.limit() + " - " + cb.position()); 位置见上文注释代码

经过打印发现

AyAvFkNuM
1024 - 1002
1024 - 1004
1024 - 1006
1024 - 1008
RcEsZqFwO
1024 - 1012
1024 - 1014
1024 - 1016
1024 - 1018
HxEsXaStX
1024 - 1022
1024 - 1024

position属性并没有随着每次调用read() 方法重置, 所以每次调用read()方法传入的是同一个 CharBuffer. 回到Scanner源码

//Scanner.java

//通过查找找到调用read()方法的地方

private void readInput() {
if (buf.limit() == buf.capacity())
makeSpace();

// Prepare to receive data
int p = buf.position();
buf.position(buf.limit());
buf.limit(buf.capacity());

int n = 0;
try { //这里调用了source.read() source就是构造方法传入的在RandomWords对象
n = source.read(buf);
} catch (IOException ioe) {
lastException = ioe;
n = -1;
}

if (n == -1) {
sourceClosed = true;
needInput = false;
}

if (n > 0)
needInput = false;

// Restore current position and limit for reading
buf.limit(buf.position());
buf.position(p);
}

发现其传入了buf参数, 查找buf来到

private Scanner(Readable source, Pattern pattern) {
assert source != null : "source should not be null";
assert pattern != null : "pattern should not be null";
this.source = source;
delimPattern = pattern;
buf = CharBuffer.allocate(BUFFER_SIZE);
buf.limit(0);
matcher = delimPattern.matcher(buf);
matcher.useTransparentBounds(true);
matcher.useAnchoringBounds(false);
useLocale(Locale.getDefault(Locale.Category.FORMAT));
}

发现是这个构造方法 对buf进行的赋值, 而 Scanner(Readable source)这个构造方法也只是调用的上一个构造方法.

所以问题解决了, 由于我是在一开始就实例化了一个Scanner对象. 导致传入read()方法的buf都是同一个 才导致的上文报错.

@2019年7月28日19:18:23@

囫囵吞枣的看完了接口
看了一部分内部类. 感觉很没有实感..
联系的太少了, 对他所说的没有感到原来如此

7月29日-8月2日

又写了一个二手交易的后台, 马上今天是八月二号, 这个假期也过了小一半了.

最近也看了看大数据相关的, 等这几天多看看关于大数据的, 也许我会选大数据专业emmm
@2019年8月2日20:22:20@
去看看ElasticSearch吧, 二手交易还差一个搜索

设置ip地址
关闭防火墙
关闭保护
删除映射管理文件
关机–>克隆四台电脑
@2019年8月2日23:42:36@

8.3-8.9

8月3日

大数据相关的删掉了, 移动到了单独的一篇博客

8月4日

大数据相关的删掉了, 移动到了单独的一篇博客

8月8日

继续学习大数据相关内容, 刷了一道算法题.待会看看Java IO流

暑期计划就到此了, 自己对于将来从事什么, 还是有些迷茫, 还是多去刷刷算法题目, 找找自己的路再走吧


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。