JavaSE

IDEA、JDK、Maven安装

《EffectiveJava》读书笔记

IO流

Java集合

枚举

  • 枚举类是用final修饰的,枚举类不能被继承!
  • 枚举类默认继承了java.lang.Enum枚举类。
  • 枚举类的第一行都是常量,存储都是枚举类的对象。
  • 枚举类的第一行必须是罗列枚举类的实例名称。
    所以:枚举类相当于是多例设计模式。
  • java建议做信息标志和信息分类应该使用枚举实现:最优雅的方式。
    可以实现可读性,而且入参受限制,不能乱输入!!!
修饰符 enum 枚举名称{
第一行都是罗列枚举实例的名称。
}
// 枚举
enum Season {
SPRING , SUMMER , AUTUMN , WINTER;
}
// 枚举类的编译以后源代码:
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();

public static Season[] values();
public static Season valueOf(java.lang.String);
}

API

// 获取当前类的全部枚举实例 : public static Season[] values()
Season[] ss = Season.values();
// 获取枚举对象的索引: ordinal()
Season s2 = Season.AUTUMN;
System.out.println(s2.ordinal()); // 2

enum Season{
SPRING, SUMMER , AUTUMN, WINTER ;
}
// 使用案例
enum Oritation{
UP , DOWN , LEFT , RIGHT ;
}

public static void move(Oritation o){
switch (o){
case UP:
System.out.println("让🐎往👆蹦~~~~");
break;
case DOWN:
System.out.println("让🐎往👇蹦~~~~");
break;
case LEFT:
System.out.println("让🐎往👈蹦~~~~");
break;
case RIGHT:
System.out.println("让🐎往👉蹦~~~~");
break;
}
}

递归

直接递归:自己的方法调用自己。

间接递归:自己的方法调用别的方法,别的方法又调用自己。

已知:f(x) = f(x - 1) + 1  (恒等式)
已知:f(1) = 1
求: f(10) = ?

计算流程:
f(10) = f(9) + 1
f(9) = f(8) + 1
f(8) = f(7) + 1
f(7) = f(6) + 1
f(6) = f(5) + 1
f(5) = f(4) + 1
f(4) = f(3) + 1
f(3) = f(2) + 1
f(2) = f(1) + 1
f(1) = 1

递归的三要素(理论):
1.递归的终结点: f(1) = 1
2.递归的公式:f(x) = f(x - 1) + 1
3.递归的方向:必须走向终结点
public static int f(int x){
if(x == 1) {
return 1;
}else{
return f(x - 1) + 1 ;
}
}
拓展:递归的核心思想-公式转换
已知: f(x) = f(x + 1) + 2
f(1) = 1
求: f(10) = ?

公式转换:
f(n-1) = f(n-1+1)+2
f(n-1) = f(n)+2
f(n) = f(n-1)- 2 ;

递归算法的三要素:
1)递归的公式: f(n) = f(n-1)- 2 ;
2)递归的终结点: f(1) = 1
3)递归的方向:必须走向终结点。
public static int f(int n){
if(n == 1) {
return 1;
}else{
return f(n-1)- 2;
}
}

递归的经典案例。

  • 猴子吃桃:
猴子第一天摘了若干个桃子,当即吃了一半,觉得好不过瘾,然后又多吃了一个。
第二天又吃了前一天剩下的一半,觉得好不过瘾,然后又多吃了一个。
以后每天都是如此
等到第十天再吃的时候发现只有1个桃子,请问猴子第一天总共摘了多少个桃子。

公式:
f(x+1) = f(x) - f(x) / 2 - 1
2f(x+1) = 2f(x) - f(x) - 2
2f(x+1) = f(x) - 2
f(x) = 2f(x+1)+2
递归的三要素:
1)公式:f(x) = 2f(x+1)+2
2)终结点:f(10) = 1
3)递归的方向:走向了终结点
public static int f(int x){
if( x == 10){
return 1 ;
}else{
return 2*f(x+1)+2;
}
}
  • 递归实现1-n的和
f(n) = 1 + 2 + 3 + 4 + 5 + 6 + ...n-1 + n ;
f(n) = f(n-1) + n

流程:
f(5) = return f(4) + 5 = 1 + 2 + 3 + 4 + 5
f(4) = return f(3) + 4 = 1 + 2 + 3 + 4
f(3) = return f(2) + 3 = 1 + 2 + 3
f(2) = return f(1) + 2 = 1 + 2
f(1) = return 1

递归的核心三要素:
(1)递归的终点接: f(1) = 1
(2)递归的公式: f(n) = f(n-1) + n
(3)递归的方向必须走向终结点:
public static int f(int n){
if(n == 1 ) return 1;
return f(n-1) + n;
}
  • n的阶乘
n!= 1*2*3*4*5*6*...*(n-1)*n。
f(n) = 1*2*3*4*5*6*...*(n-1)*n
f(n) = f(n-1)*n

流程:
f(5) = f(4) * 5 ; = 1*2*3*4*5
f(4) = f(3) * 4 ; = 1*2*3*4
f(3) = f(2) * 3 ; = 1*2*3
f(2) = f(1) * 2 ; = 1*2
f(1) = 1

递归的核心三要素:
(1)递归的终点接: f(1) = 1
(2)递归的公式 f(n) = f(n-1)*n
(3)递归的方向必须走向终结点
public static int f(int n){
if(n == 1){
return 1 ;
}else{
return f(n-1)*n;
}
}
  • 递归实现文件搜索(非规律递归)
需求:希望去D:/soft目录寻找出eclipse.exe文件。

分析:
(1)定义一个方法用于做搜索。
(2)进入方法中进行业务搜索分析。
小结:
非规律化递归应该按照业务流程开发!
/**
* 去某个目录下搜索某个文件
* @param dir 搜索文件的目录。
* @param fileName 搜索文件的名称。
*/
public static void searchFiles(File dir , String fileName){
// 1.判断是否存在该路径,是否是文件夹
if(dir.exists() && dir.isDirectory()){
// 2.提取当前目录下的全部一级文件对象
File[] files = dir.listFiles(); // null/[]
// 3.判断是否存在一级文件对象(判断是否不为空目录)
if(files!=null && files.length > 0){
// 4.判断一级文件对象
for (File f : files) {
// 5.判断file是文件还是文件夹
if(f.isFile()){
// 6.判断该文件是否为我要找的文件对象
if(f.getName().contains(fileName)){
System.out.println(f.getAbsolutePath());
try {
// 启动它(拓展)
Runtime r = Runtime.getRuntime();
r.exec(f.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}else{
// 7.该文件是文件夹,文件夹要递归进入继续寻找
searchFiles(f ,fileName);
}
}
}
}
}

日志级别

日志级别 描述
OFF 关闭:最高级别,不打印日志。
FATAL 致命:指明非常严重的可能会导致应用终止执行错误事件。 灾难信息,合并计入ERROR
ERROR 错误:指明错误事件,但应用可能还能继续运行。 记录错误堆栈信息
WARN 警告:指明可能潜在的危险状况。 记录运维过程报警数据
INFO 信息:指明描述信息,从粗粒度上描述了应用运行过程。 记录运维过程数据
DEBUG 调试:指明细致的事件信息,对调试应用最有用。 程序员调试代码使用
TRACE 跟踪:指明程序运行轨迹,比DEBUG级别的粒度更细。 运行堆栈信息,使用率低
ALL 所有:所有日志级别,包括定制级别

ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

设置日志组,控制指定包对应的日志输出级别,也可以直接控制指定包对应的日志输出级别

# 开启debug模式,输出调试信息,常用于检查系统运行状况
debug: true

# 设置日志级别,root表示根节点,即整体应用日志级别
logging:
level:
root: debug

# 关闭运行日志图表(banner)
spring:
main:
banner-mode: off

日志文件

logging:
file:
name: server.log
logback:
rollingpolicy:
max-file-size: 3KB
file-name-pattern: server.%d{yyyy-MM-dd}.%i.log

日志输出格式控制

logging:
pattern:
console: "%d %clr(%p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"

时间复杂度

在上图中,我们可以看到当 n 很小时,函数之间不易区分,很难说谁处于主导地位,但是当 n 增大时,我们就能看到很明显的区别,谁是老大一目了然:

O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)

出处:https://blog.csdn.net/chenguanghan123/article/details/83478259

如果ax=N(a>0,且a≠1),那么数x叫做以a为底N的对数,记作x=logaN,读作以a为底N的对数,其中a叫做对数的底数,N叫做真数。

出处:https://blog.csdn.net/ted_cs/article/details/82881831

Java API

Spring 最常用工具类汇总

jar包位置 spring-core.jar

1.访问文件资源

假设有一个文件地位于 Web 应用的类路径下,您可以通过以下方式对这个文件资源进行访问:

FileSystemResource 以文件系统绝对路径的方式进行访问;
ClassPathResource 以类路径的方式进行访问;
ServletContextResource 以相对于 Web 应用根目录的方式进行访问。
ResourceUtils 它支持“classpath:”和“file:”的地址前缀,它能够从指定的地址加载文件资源,常用方法:getFile()

2.本地化文件资源

LocalizedResourceHelper 允许通过文件资源基名和本地化实体获取匹配的本地化文件资源并以 Resource 对象返回

3.文件操作

FileCopyUtils,它提供了许多一步式的静态操作方法,能够将文件内容拷贝到一个目标 byte[]、String 甚至一个输出流或输出文件中。

4.属性文件操作

PropertiesLoaderUtils 允许您直接通过基于类路径的文件地址加载属性资源

5.特殊编码的资源

EncodedResource 当您使用 Resource 实现类加载文件资源时,它默认采用操作系统的编码格式。如果文件资源采用了特殊的编码格式(如 UTF-8),则在读取资源内容时必须事先通过 EncodedResource 指定编码格式,否则将会产生中文乱码的问题。

6.操作 Servlet API 的工具类

WebApplicationContextUtils 工具类获取 WebApplicationContext 对象

WebApplicationContext wac =WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);

7.WebUtils

主要方法:

// 获取 HttpServletRequest 中特定名字的Cookie 对象。
// 如果您需要创建 Cookie, Spring 也提供了一个方便的 CookieGenerator 工具类;
.getCookie(HttpServletRequest request, String name);

// 获取 HttpSession 特定属性名的对象,否则您必须通过 request.getHttpSession.getAttribute(name) 完成相同的操作;
.getSessionAttribute(HttpServletRequest request, String name);

// 和上一个方法类似,只不过强制要求 HttpSession 中拥有指定的属性,否则抛出异常;
.getRequiredSessionAttribute(HttpServletRequest request, String name);

// 获取 Session ID 的值;
.getSessionId(HttpServletRequest request);

// 将 Map 元素添加到 ServletRequest 的属性列表中,当请求被导向(forward)到下一个处理程序时,这些请求属性就可以被访问到了;
void exposeRequestAttributes(ServletRequest request, Map attributes);

8.延迟加载过滤器

OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service 层使用 HibernateTransactionManager 或 JtaTransactionManager 进行事务管理的环境,也可以用于非事务只读的数据操作中。

9.中文乱码过滤器

CharacterEncodingFilter 当通过表单向服务器提交数据时,一个经典的问题就是中文乱码问题。虽然我们所有的 JSP 文件和页面编码格式都采用 UTF-8,但这个问题还是会出现。解决的办法很简单,我们只需要在 web.xml 中配置一个 Spring 的编码转换过滤器就可以了

10.请求跟踪日志过滤器

ServletContextRequestLoggingFilter 在日志级别为 DEBUG 时才会起作用

11.监听器配置

WebAppRootListener
Log4J 监听器 Log4jConfigListener
缓存清除监听器 IntrospectorCleanupListener

12.特殊字符转义

HTML 特殊字符转义
HtmlUtils 常用方法 htmlEscape(),htmlUnescape()

JavaScript 特殊字符转义
JavaScriptUtils 常用方法:javaScriptEscape

SQL特殊字符转义 (引入 jakarta commons lang 类包)
StringEscapeUtils 常用方法: escapeSql

13.方法入参检测工具类

Assert 常用方法:

notNull(Object object)
notNull(Object object, String message);

isNull(Object object)
isNull(Object object, String message);

isTrue(boolean expression)
isTrue(boolean expression, String message);

notEmpty(Collection collection)
notEmpty(Collection collection, String message);

notEmpty(Map map)
notEmpty(Map map, String message)

notEmpty(Object[] array, String message)
notEmpty(Object[] array, String message)

hasLength(String text)
hasLength(String text, String message);

hasText(String text)
hasText(String text, String message)

// 如果 obj 不能被正确造型为 clazz 指定的类,将抛出异常;
isInstanceOf(Class clazz, Object obj)
isInstanceOf(Class type, Object obj, String message)

// subType 必须可以按类型匹配于 superType,否则将抛出异常;
isAssignable(Class superType, Class subType)
isAssignable(Class superType, Class subType, String message)

14.请求工具类 ServletRequestUtils

// 取请求参数的整数值:
public static Integer getIntParameter(ServletRequest request, String name)

// 单个值
public static int getIntParameter(ServletRequest request, String name, int defaultVal)

// 数组
public static int[] getIntParameters(ServletRequest request, String name)

还有譬如longfloatdoubleboolean、String的相关处理方法。

15. 字符串工具类

org.springframework.util.StringUtils

// 首字母大写
public static String capitalize(String str)

// 首字母小写
public static String uncapitalize(String str)

// 判断字符串是否为null或empty
public static boolean hasLength(String str)

// 判断字符串是否为非空白字符串(即至少包含一个非空格的字符串)
public static boolean hasText(String str)

// 获取文件名:如: "mypath/myfile.txt" -> "myfile.txt"
public static String getFilename(String path)

// 获取文件扩展名:如"mypath/myfile.txt" -> "txt"
public static String getFilenameExtension(String path)

还有譬如数组转集合、集合转数组、路径处理、字符串分离成数组、数组或集合合并为字符串、数组合并、向数组添加元素等。

15.1集合工具类 CollectionUtils

// 判断集合是否为空 
CollectionUtils.isEmpty(集合);

16.对象序列化与反序列化

org.springframework.util.SerializationUtils

public static byte[] serialize(Object object)

public static Object deserialize(byte[] bytes)

17.数字处理

org.springframework.util.NumberUtils

// 字符串转换为Number并格式化,包括具体的Number实现类,
// 如Long、Integer、Double,字符串支持16进制字符串,并且会自动去除字符串中的空格:
public static <T extends Number> T parseNumber(String text, Class<T> targetClass)
public static <T extends Number> T parseNumber(String text, Class<T> targetClass, NumberFormat numberFormat)

// 各种Number中的转换,如Long专为Integer,自动处理数字溢出(抛出异常):
public static <T extends Number> T convertNumberToTargetClass(Number number, Class<T> targetClass)

18.目录复制

org.springframework.util.FileSystemUtils 递归复制、删除一个目录

19.MD5加密

org.springframework.util.DigestUtils

// 字节数组的MD5加密 
public static String md5DigestAsHex(byte[] bytes)

xml工具

org.springframework.util.xml.AbstractStaxContentHandler
org.springframework.util.xml.AbstractStaxXMLReader
org.springframework.util.xml.AbstractXMLReader
org.springframework.util.xml.AbstractXMLStreamReader
org.springframework.util.xml.DomUtils
org.springframework.util.xml.SimpleNamespaceContext
org.springframework.util.xml.SimpleSaxErrorHandler
org.springframework.util.xml.SimpleTransformErrorListener
org.springframework.util.xml.StaxUtils
org.springframework.util.xml.TransformerUtils

其它工具集

org.springframework.util.AntPathMatcherant 风格的处理
org.springframework.util.AntPathStringMatcher
org.springframework.util.Assert 断言,在我们的参数判断时应该经常用
org.springframework.util.CachingMapDecorator
org.springframework.util.ClassUtils 用于Class的处理
org.springframework.util.CollectionUtils 用于处理集合的工具
org.springframework.util.CommonsLogWriter
org.springframework.util.CompositeIterator
org.springframework.util.ConcurrencyThrottleSupport
org.springframework.util.CustomizableThreadCreator
org.springframework.util.DefaultPropertiesPersister
org.springframework.util.DigestUtils 摘要处理, 这里有用于md5处理信息的
org.springframework.util.FileCopyUtils 文件的拷贝处理, 结合Resource的概念一起来处理, 真的是很方便
org.springframework.util.FileSystemUtils
org.springframework.util.LinkedCaseInsensitiveMap key值不区分大小写的LinkedMap
org.springframework.util.LinkedMultiValueMap 一个key可以存放多个值的LinkedMap
org.springframework.util.Log4jConfigurer 一个log4j的启动加载指定配制文件的工具类
org.springframework.util.NumberUtils 处理数字的工具类, 有parseNumber 可以把字符串处理成我们指定的数字格式, 还支持format格式, convertNumberToTargetClass 可以实现Number类型的转化.
org.springframework.util.ObjectUtils 有很多处理null object的方法. 如nullSafeHashCode, nullSafeEquals, isArray, containsElement, addObjectToArray, 等有用的方法
org.springframework.util.PatternMatchUtils spring里用于处理简单的匹配. 如 Spring's typical &quot;xxx*&quot;, &quot;*xxx&quot; and &quot;*xxx*&quot; pattern styles
org.springframework.util.PropertyPlaceholderHelper 用于处理占位符的替换
org.springframework.util.ReflectionUtils 反映常用工具方法. 有 findField, setField, getField, findMethod, invokeMethod等有用的方法
org.springframework.util.SerializationUtils 用于java的序列化与反序列化. serialize与deserialize方法
org.springframework.util.StopWatch 一个很好的用于记录执行时间的工具类, 且可以用于任务分阶段的测试时间. 最后支持一个很好看的打印格式. 这个类应该经常用
org.springframework.util.xSystemPropertyUtils
org.springframework.util.TypeUtils 用于类型相容的判断. isAssignable
org.springframework.util.WeakReferenceMonitor 弱引用的监控

web相关的工具

org.springframework.web.util.CookieGenerator
org.springframework.web.util.HtmlCharacterEntityDecoder
org.springframework.web.util.HtmlCharacterEntityReferences
org.springframework.web.util.HtmlUtils
org.springframework.web.util.HttpUrlTemplate 这个类用于用字符串模板构建url, 它会自动处理url里的汉字及其它相关的编码. 在读取别人提供的url资源时, 应该经常用 String url = &quot;http://localhost/myapp/{name}/{id}&quot;
org.springframework.web.util.JavaScriptUtils
org.springframework.web.util.Log4jConfigListener 用listener的方式来配制log4j在web环境下的初始化
org.springframework.web.util.UriTemplate
org.springframework.web.util.UriUtils 处理uri里特殊字符的编码
org.springframework.web.util.WebUtils

SpringUtil工具类

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.util.Map;

/**
* Spring工具类
*/
@Slf4j
@Component
public class SpringUtil implements ApplicationContextAware {

/**
* spring全局配置项
*/
private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
if (applicationContext == null) {
applicationContext = context;
log.info("ApplicationContext init success,you can invoke by SpringUtil.getApplicationContext() to get ApplicationContext,init bean count="
+ applicationContext.getBeanDefinitionCount() + ",bean=" + JSONObject.toJSONString(applicationContext.getBeanDefinitionNames()));
}
}

/**
* @return spring全局配置项
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}

/**
* 通过name获取 Bean.
*
* @param name
* @return
*/
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}

/**
* 通过class获取Bean.
*
* @param clazz
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}

/**
* 通过name,以及Clazz返回指定的Bean
*
* @param name
* @param clazz
* @return
*/
public static <T> T getBean(String name, Class<T> clazz) {
return applicationContext.getBean(name, clazz);
}

/**
* 获取实现相关接口的类关系
*
* @param clazz
* @return
*/
public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
return applicationContext.getBeansOfType(clazz);
}

/**
* 发布事件
*
* @param event
*/
public static void publishEvent(ApplicationEvent event) {
applicationContext.publishEvent(event);
}

/**
* 获取环境信息
*/
public static Environment getEnvironment() {
return applicationContext.getEnvironment();
}

}

Java正则表达式

https://www.runoob.com/regexp/regexp-syntax.html

字符类
[abc] abc(简单类)
[^abc] 任何字符,除了 abc(否定)
[a-zA-Z] azAZ,两头的字母包括在内(范围)
[a-d[m-p]] admp[a-dm-p](并集)
[a-z&&[def23]] def(交集)
[a-z&&[^bc]] az,除了 bc[ad-z](减去)
[a-z&&[^m-p]] az,而非 mp[a-lq-z](减去)

预定义字符类
. 任何字符
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]

以上正则匹配只能校验单个字符。

Greedy 数量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n
X{n,} X,至少 n
X{n,m} X,至少 n 次,但是不超过 m
public String[] split(String regex);// 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
public String replaceAll(String regex,String newStr);// 按照正则表达式匹配的内容进行替换

正则表达式爬取信息中的内容

public class RegexDemo05 {
public static void main(String[] args) {
String rs = "来黑马程序学习java,电话020-43422424,或者联系邮箱" +
"itcast@itcast.cn,电话18762832633,0203232323" +
"邮箱bozai@itcast.cn,400-100-3233 ,4001003232";
// 需求:从上面的内容中爬取出 电话号码和邮箱。
// 1.定义爬取规则
String regex = "(\\w{1,}@\\w{2,10}(\\.\\w{2,10}){1,2})|(1[3-9]\\d{9})|(0\\d{2,5}-?\\d{5,15})|400-?\\d{3,8}-?\\d{3,8}";
// 2.编译正则表达式成为一个匹配规则对象
Pattern pattern = Pattern.compile(regex);
// 3.通过匹配规则对象得到一个匹配数据内容的匹配器对象
Matcher matcher = pattern.matcher(rs);
// 4.通过匹配器去内容中爬取出信息
while(matcher.find()){
System.out.println(matcher.group());
}
}
}

Java定时任务

// TimerTask  单线程
private static void timerTask() throws InterruptedException {
Timer timer = new Timer();

TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("hi, 欢迎关注:java技术栈");
}
};

// 第一次任务延迟时间
long delay = 2000;

// 任务执行频率
long period = 3 * 1000;

// 开始调度
timer.schedule(timerTask, delay, period);

// 指定首次运行时间
// timer.schedule(timerTask, DateUtils.addSeconds(new Date(), 5), period);

Thread.sleep(20000);

// 终止并移除任务
timer.cancel();
timer.purge();
}

Java算法

冒泡排序

冒泡排序的核心算法思想:
int[] arr = new int[] {55, 22, 99, 88};
思想:每次从数组的第一个位置开始两两比较。把较大的元素与较小的元素进行层层交换。
最终把当前最大的一个元素存入到数组当前的末尾。这就是冒泡思想。

冒泡排序的实现核心:
1.确定总共需要冒几轮: 数组的长度-1.
2.每轮两两比较几次。
i(轮数) 次数 每轮次数的规律:数组长度-i-1
0 3
1 2
2 1
public static void BubbleSort(int[] arr) {
int temp;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j + 1] < arr[j]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}

️选择排序

package com.zx._10排序算法冒泡_选择_排序;

import java.util.Arrays;

/**
目标:选择排序。

选择排序的思想:从当前位置开始找出后面的较小值与该位置交换。
数组:int[] arr = {5 , 1 , 3 , 2}

选择排序的实现思路:
(1)控制选择几轮:数组的长度-1.
(2)控制每轮从当前位置开始比较几次。

i(轮数) 次数
0 3
1 2
2 1
小结:
从当前位置开始找出后面的较小值与该位置交换。
控制选择几轮:数组的长度-1.
以当前位置作为基准,从下一个元素开始遍历寻找出较小值与当前位置交换即可!
*/
public class SelectSort02 {
public static void main(String[] args) {
int[] arr = {5 , 1 , 3 , 2};
// 1.定义一个循环控制选择几轮
for(int i = 0 ; i < arr.length - 1 ; i++ ){
// 2.定义一个循环控制每轮比较几次,一定是以当前位置与后面元素比较
// i =0 j = 1 2 3
// i =1 j = 2 3
// i =2 j = 3
// 遍历后面的元素
for(int j = i+1 ; j < arr.length ; j++ ){
// 拿当前位置与j指定的元素进行大小比较,后面的较小就交换位置
if(arr[j] < arr[i]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println("数组:"+ Arrays.toString(arr));
}
}

️二分查找

package com.zx._11二分查找提高检索性能;

/**
目标:二分查找。

正常查找:从第一个元素开始遍历,一个一个的往后找,综合查找比较耗时。
二分查找:二分查找的前提:对数组是有要求的,数组必须已经排好序。
每次先与中间的元素进行比较,如果大于往右边找,如果小于往左边找,如果等于就返回该元素索引位置!
如果没有该元素,返回-1。综合性能比较好!!
小结:
定义一个方法,记录开始的索引位置和结束的索引位置。
取出中间索引位置的值,拿元素与中间位置的值进行比较,如果小于中间值,结束位置=中间索引-1.
取出中间索引位置的值,拿元素与中间位置的值进行比较,如果大于中间值,开始位置=中间索引+1.
循环正常执行的条件是:开始位置索引<=结束位置索引。 否则说明寻找完毕但是还是没有该元素值返回了-1.

*/
public class BinarySerach {
public static void main(String[] args) {
// 1.数组
int[] arr = {10, 14, 21, 38, 45, 47, 53, 81, 87, 99};
// 2.需求是从数组中二分查询某个元素值的索引(提高性能)
System.out.println("81的索引是:"+binarySerach(arr,23));
}

/**
*
* @param arr 被检索的数组
* @param number 被检索的元素值
* @return 返回元素在数组中的索引值,不存在该元素返回-1
*/
public static int binarySerach(int[] arr , int number){
// 3.记录当前区间搜索的开始索引和结束索引。
int start = 0 ;
int end = arr.length - 1;
// 4.定义一个循环,反复去循环元素。
while(start <= end){
// 5.取中间索引位置
int middleIndex = (start + end) / 2 ;
// 6.判断当前元素与中间元素的大小
if(number < arr[middleIndex]){
// 7.往左边继续寻找,结束索引应该-1
end = middleIndex - 1;
}else if(number > arr[middleIndex]){
start = middleIndex + 1;
}else if(number == arr[middleIndex]){
return middleIndex;
}
}
// 如果上述循环执行完毕还没有返回索引,说明根本不存在该元素值,直接返回-1
return -1;
}
}

插入排序

雪花算法

//雪花算法代码实现
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits +
datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;

public IdWorker() {
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}

/**
* @param workerId 工作机器ID
* @param datacenterId 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than % d or less than 0", maxWorkerId)); }
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than % d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}

/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds ", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}

private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}

private long timeGen() {
return System.currentTimeMillis();
}

/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
// GET jvmPid
mpid.append(name.split("@")[0]);
}
// MAC + PID 的 hashcode 获取16个低位
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}

/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}
}

Java工具类

BigDicimal类

public static BigDecimal valueOf(double val);// 包装浮点数成为大数据对象。创建对象的方式(最好的方式:)
public BigDecimal add(BigDecimal value);// 加法运算
public BigDecimal subtract(BigDecimal value);// 减法运算
public BigDecimal multiply(BigDecimal value);// 乘法运算
public BigDecimal divide(BigDecimal value);// 除法运算
public double doubleValue();// 把BigDecimal转换成double类型。

// 1.把浮点数转换成大数据对象运算
double a = 0.1 ;
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
BigDecimal c1 = a1.add(b1); // 加法
BigDecimal c1 = a1.divide(b1); // 除法

// BigDecimal只是解决精度问题的手段,double数据才是我们的目的!!
double rs = c1.doubleValue();
package com.zx._05BigDecimal计算浮点型;


import java.math.BigDecimal;

/**
目标:BigDecimal大数据类。

引入:
浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
BigDecimal可以解决浮点型运算数据失真的问题。

BigDicimal类:
包:java.math.
创建对象的方式(最好的方式:)
public static BigDecimal valueOf(double val) :包装浮点数成为大数据对象。
方法声明
public BigDecimal add(BigDecimal value) 加法运算
public BigDecimal subtract(BigDecimal value) 减法运算
public BigDecimal multiply(BigDecimal value) 乘法运算
public BigDecimal divide(BigDecimal value) 除法运算
public double doubleValue():把BigDecimal转换成double类型。
*/
public class BigDecimalDemo {
public static void main(String[] args) {
// 浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
System.out.println(0.1 + 0.2);
System.out.println(0.09 + 0.01);
System.out.println(1.0 - 0.32);
System.out.println(1.015 * 100);
System.out.println(1.301 / 100);

System.out.println("-------------------------");
double a = 0.1 ;
double b = 0.2 ;
double c = a + b ;
System.out.println(c);

// 1.把浮点数转换成大数据对象运算
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
//BigDecimal c1 = a1.add(b1); // 加法
BigDecimal c1 = a1.divide(b1); // 除法
System.out.println(c1);

// 结果可能需要继续使用!!!
// BigDecimal只是解决精度问题的手段,double数据才是我们的目的!!
double rs = c1.doubleValue();
System.out.println(rs);
}
}

System系统类

public static void exit(int status);// 终止JVM虚拟机,非0是异常终止。
public static long currentTimeMillis();// 获取当前系统此刻时间毫秒值。

arraycopy(Object src,int srcPos ,Object dest, int destPos, int length);// 可以做数组的拷贝(了解)
// 参数一:原数组
// 参数二:从哪个索引位置开始赋值
// 参数三:目标数组
// 参数四:目标数组的开始索引:
// 参数五:复制几个
int[] arrs1 = new int[]{10 ,20 ,30 ,40 ,50 ,60 ,70};
int[] arrs2 = new int[6]; // [ 0 , 0 , 0 , 0 , 0 , 0]
System.arraycopy(arrs1,2, arrs2 , 1 , 3);// arrs2 = [0 , 30 , 40 , 50 , 0 , 0 ]

System.exit(0); // 终止当前虚拟机 0代表正常终止!!
long time = System.currentTimeMillis();// 得到系统当前时间毫秒值
package com.zx._04System系统类的使用;

import java.text.SimpleDateFormat;
import java.util.Arrays;

/**
目标:System系统类的使用。
System代表当前系统。
静态方法:
1.public static void exit(int status):终止JVM虚拟机,非0是异常终止。
2.public static long currentTimeMillis():获取当前系统此刻时间毫秒值。
3.可以做数组的拷贝。
arraycopy(Object var0, int var1, Object var2, int var3, int var4);
* 参数一:原数组
* 参数二:从原数组的哪个位置开始赋值。
* 参数三:目标数组
* 参数四:赋值到目标数组的哪个位置
* 参数五:赋值几个。
*/
public class SystemDemo {
public static void main(String[] args) {
System.out.println("程序开始。。。");

// 1.终止当前虚拟机
//System.exit(0); // 0代表正常终止!!

// 2.得到系统当前时间毫秒值
long time = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(sdf.format(time));

// 3.可以做数组的拷贝(了解)
int[] arrs1 = new int[]{10 ,20 ,30 ,40 ,50 ,60 ,70};
int[] arrs2 = new int[6]; // [ 0 , 0 , 0 , 0 , 0 , 0]
// arrs2 = [0 , 30 , 40 , 50 , 0 , 0 ]
/**
arraycopy(Object src,int srcPos ,Object dest, int destPos, int length)
参数一:原数组
参数二:从哪个索引位置开始赋值
参数三:目标数组
参数四:目标数组的开始索引:
参数五:复制几个
*/
System.arraycopy(arrs1,2, arrs2 , 1 , 3);
System.out.println(Arrays.toString(arrs2));

System.out.println("程序结束。。。");
}
}

java.lang.Math

public static int abs(int a);                  // 获取参数a的绝对值:
public static double ceil(double a); // 向上取整 Math.ceil(4.00000001); // 5.0
public static double floor(double a); // 向下取整 Math.floor(4.99999999); // 4.0
public static double pow(double a, double b); // 获取a的b次幂 Math.pow(2 , 3); // 2^3 = 8.0
public static long round(double a); // 四舍五入取整 Math.round(4.49999); // 4 Math.round(4.500001); // 5

java.time.LocalDateTime

LocalDateTime currentTime = LocalDateTime.now(); // 获取当前的日期时间
LocalDate date = currentTime.toLocalDate();
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();

LocalDateTime date = currentTime.withDayOfMonth(10).withYear(2012);

// 12 december 2014
LocalDate date = LocalDate.of(2014, Month.DECEMBER, 12);

// 22 小时 15 分钟
LocalTime date = LocalTime.of(22, 15);

// 解析字符串
LocalTime date = LocalTime.parse("20:15:30");

️SimpleDateFormat

public String format(Date date);// 可以把日期对象格式化成我们喜欢的时间形式,返回的是字符串!
public String format(Object time);// 可以把时间毫秒值格式化成我们喜欢的时间形式,返回的是字符串!
public Date parse(String date) throws ParseException;// 把字符串的时间解析成日期对象

// 得到此刻日期对象
Date date = new Date();
// 得到当前时间的时间毫秒值
long time = date.getTime();
// 创建一个简单日期格式化对象负责格式化日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
// 格式化时间得到格式化的字符串时间形式
String rs = sdf.format(date);
// 格式化时间毫秒值
String rs = sdf.format(time);
String date = "2019-11-04 09:30:30";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date newDate = sdf.parse(date);

并发编程

多线程

程序是静止的,运行中的程序就是进程。
进程的三个特征:
1.动态性 : 进程是运行中的程序,要动态的占用内存,CPU和网络等资源。
2.独立性 : 进程与进程之间是相互独立的,彼此有自己的独立内存区域。
3.并发性 : 假如CPU是单核,同一个时刻其实内存中只有一个进程在被执行。
CPU会分时轮询切换依次为每个进程服务,因为切换的速度非常
快,给我们的感觉这些进程在同时执行,这就是并发性。
什么是线程?
线程是属于进程的。一个进程可以包含多个线程,这就是多线程。
线程是进程中的一个独立执行单元。
线程创建开销相对于进程来说比较小。
线程也支持“并发性”。

线程的创建方式

a.继承Thread类的方式
-- 1.定义一个线程类继承Thread类。
-- 2.重写run()方法
-- 3.创建一个新的线程对象。
-- 4.调用线程对象的start()方法启动线程。

注意:
1.线程的启动必须调用start()方法。否则当成普通类处理。
-- 如果线程直接调用run()方法,相当于变成了普通类的执行,此时将只有主线程在执行他们!
-- start()方法底层其实是给CPU注册当前线程,并且触发run()方法执行
2.建议线程先创建子线程,主线程的任务放在之后。否则主线程永远是先执行完!
Thread t = new MyThread();
t.start()

class MyThread extends Thread{
@Override
public void run() {
for(int i = 0 ; i < 100 ; i++ ){
System.out.println("子线程输出:"+i);
}
}
}
Thread类的API

1.public void setName(String name):给当前线程取名字。
2.public void getName():获取当前线程的名字。
-- 线程存在默认名称,子线程的默认名称是:Thread-索引。
-- 主线程的默认名称就是:main
3.public static Thread currentThread()
-- 获取当前线程对象,这个代码在哪个线程中,就得到哪个线程对象。
4.public static void sleep(long time): 让当前线程休眠多少毫秒再继续执行。
-- public Thread()
-- public Thread(String name):创建线程对象并取名字。
b.实现Runnable接口的方式。
-- 1.创建一个线程任务类实现Runnable接口。
-- 2.重写run()方法
-- 3.创建一个线程任务对象。
-- 4.把线程任务对象包装成线程对象
-- 5.调用线程对象的start()方法启动线程。
Thread的构造器:
-- public Thread(){}
-- public Thread(String name){}
-- public Thread(Runnable target){}
-- public Thread(Runnable target,String name){}

实现Runnable接口创建线程的优缺点:
缺点:代码复杂一点。
优点:
-- 线程任务类只是实现了Runnable接口,可以继续继承其他类,而且可以继续实现其他接口(避免了单继承的局限性)
-- 同一个线程任务对象可以被包装成多个线程对象
-- 适合多个多个线程去共享同一个资源(后面内容)
-- 实现解耦操作,线程任务代码可以被多个线程共享,线程任务代码和线程独立。
-- 线程池可以放入实现Runable或Callable线程任务对象。(后面了解)
注意:其实Thread类本身也是实现了Runnable接口的。
-- 不能直接得到线程执行的结果!
Runnable target = new MyRunnable();
Thread t = new Thread(target);
t.start();

class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0 ; i < 10 ; i++ ){
System.out.println(Thread.currentThread().getName()+"==>"+i);
}
}
}

// 匿名内部类写法
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0 ; i < 10 ; i++ ){
System.out.println(Thread.currentThread().getName()+"==>"+i);
}
}
}).start();
c.线程的创建方式三: 实现Callable接口。
-- 1,定义一个线程任务类实现Callable接口 , 申明线程执行的结果类型。
-- 2,重写线程任务类的call方法,这个方法可以直接返回执行的结果。
-- 3,创建一个Callable的线程任务对象。
-- 4,把Callable的线程任务对象包装成一个未来任务对象。
-- 5.把未来任务对象包装成线程对象。
-- 6.调用线程的start()方法启动线程
优点:全是优点。
-- 线程任务类只是实现了Callable接口,可以继续继承其他类,而且可以继续实现其他接口(避免了单继承的局限性)
-- 同一个线程任务对象可以被包装成多个线程对象
-- 适合多个多个线程去共享同一个资源(后面内容)
-- 实现解耦操作,线程任务代码可以被多个线程共享,线程任务代码和线程独立。
-- 线程池可以放入实现Runable或Callable线程任务对象。(后面了解)
-- 能直接得到线程执行的结果!
缺点:编码复杂。
Callable call = new MyCallable();
// 4.把Callable任务对象包装成一个未来任务对象
// -- public FutureTask(Callable<V> callable)
// 未来任务对象是啥,有啥用?
// -- 未来任务对象其实就是一个Runnable对象:这样就可以被包装成线程对象!
// -- 未来任务对象可以在线程执行完毕之后去得到线程执行的结果。
FutureTask<String> task = new FutureTask<>(call);
// 5.把未来任务对象包装成线程对象
Thread t = new Thread(task);
// 6.启动线程对象
t.start();

// 在最后去获取线程执行的结果,如果线程没有结果,让出CPU等线程执行完再来取结果
try {
String rs = task.get(); // 获取call方法返回的结果(正常/异常结果)
System.out.println(rs);
} catch (Exception e) {
e.printStackTrace();
}

// 1.创建一个线程任务类实现Callable接口,申明线程返回的结果类型
class MyCallable implements Callable<String>{
// 2.重写线程任务类的call方法!
@Override
public String call() throws Exception {
// 需求:计算1-10的和返回
int sum = 0 ;
for(int i = 1 ; i <= 10 ; i++ ){
System.out.println(Thread.currentThread().getName()+" => " + i);
sum+=i;
}
return Thread.currentThread().getName()+"执行的结果是:"+sum;
}
}

线程同步_同步代码块

线程同步的方式有三种:
(1)同步代码块。
(2)同步方法。
(3)lock显示锁。

a.同步代码块。
synchronized(锁对象){
// 访问共享资源的核心代码
}
锁对象:理论上可以是任意的“唯一”对象即可。
原则上:锁对象建议使用共享资源。
-- 在实例方法中建议用this作为锁对象。此时this正好是共享资源!必须代码高度面向对象
-- 在静态方法中建议用类名.class字节码作为锁对象。
b.同步方法
方法加上一个修饰符 synchronized.
public synchronized void drawMoney(double money)
同步方法其实底层也是有锁对象的:
如果方法是实例方法:同步方法默认用this作为的锁对象。
如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
c.lock显示锁。
java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,
同步代码块/同步方法具有的功能Lock都有,除此之外更强大

Lock锁也称同步锁,加锁与释放锁方法化了,如下:
- `public void lock() `:加同步锁。
- `public void unlock()`:释放同步锁。
public void drawMoney(double money) {
// 1.先拿到是谁来取钱:取当前线程对象的名称
String name = Thread.currentThread().getName();
lock.lock(); // 上锁~!
try{
// ..
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock(); // 解锁~!
}
}

字符集/编码集

1B = 8b 计算机中的最小单位是字节B.

一个字节8位,2^8 = 256
ASCII编码:ASCII它是一种7位编码,但它存放时必须占全一个字节,也即占用8位。
a 97
b 98
A 65
B 66
0 48
1 49

GBK编码:2个字节
Unicode编码(万国码):
UTF-83个字节

英文和数字在任何编码集中都是一样的,都占1个字节。
英文和数字在任何编码集中可以通用,不会乱码!!
GBK编码中,1个中文字符一般占2个字节。
UTF-8编码中,1个中文字符一般占3个字节。

泛型

泛型接口

修饰符 interface 接口名称<泛型变量>{

}
public interface Data<E> {
void add(E stu);

void delete(E stu);

void update(E stu);

E query(int id);
}

// 操作学生数据
public class StudentData implements Data<Student> {
@Override
public void add(Student stu) {
System.out.println("添加学生!");
}

@Override
public void delete(Student stu) {
System.out.println("删除学生!");
}

@Override
public void update(Student stu) {
}

@Override
public Student query(int id) {
return null;
}
}

泛型通配符

通配符:?
?可以用在使用泛型的时候代表一切类型。
E , T , K , V是在定义泛型的时候使用代表一切类型。

泛型的上下限:
? extends Car : 那么?必须是Car或者其子类。(泛型的上限)
? super Car :那么?必须是Car或者其父类。(泛型的下限。不是很常见)
public class GenericDemo {
public static void main(String[] args) {
ArrayList<BMW> bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
run(bmws);

ArrayList<BENZ> benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
benzs.add(new BENZ());
run(benzs);

ArrayList<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
// run(dogs); // 就进不来了!
}

// 定义一个方法,可以让很多汽车一起进入参加比赛
public static void run(ArrayList<? extends Car> cars) {

}
}

class Car {
}

class BMW extends Car {
}

class BENZ extends Car {
}

class Dog {
}

自定义泛型方法

修饰符 <泛型变量> 返回值类型 方法名称(形参列表){

}

class class1 {
public static <T> String arrToString(T[] nums) {
StringBuilder sb = new StringBuilder();
sb.append("[");
if (nums != null && nums.length > 0) {
for (int i = 0; i < nums.length; i++) {
T ele = nums[i];
sb.append(i == nums.length - 1 ? ele : ele + ", ");
}
}
sb.append("]");
return sb.toString();
}
}

自定义泛型类

修饰符 class 类名<泛型变量>{

}
泛型变量建议使用 E , T , K , V
class MyArrayList<E> {
private ArrayList lists = new ArrayList();

public void add(E e) {
lists.add(e);
}

public void remove(E e) {
lists.remove(e);
}

@Override
public String toString() {
return lists.toString();
}
}

Java语言-相关书籍

Java语言-资源

Java面试


临时笔记

  • 推荐:优先使用不可变的类 LocalDate
  • 不推荐使用:Switch语句 goto语句 char类型 int i, j
  • Character类的 isJavaIdentifierStart isJavaIdentifierPart
  • 15/2 = 7 15%2 = 1 15.0/2 = 7.5
    整数被0除→异常
    浮点数被0除→无穷大或NaN
  • strictfp
  • Math.sprt(x) 平方根
    Math.pow(x,a) 幂运算
    Math.PI π的近似值
    Math.E e的近似值
  • StrictMath类 得到一个完全可预测的结果,速度比Math差
  • int[ ] arrs2= Arrays.copyof(arrs1,arrs1.length)
    int[ ] arrs = Arrays.copyof(arrs,2*arrs.length)
    int[ ] a = new int[4]
    int[ ] a = {1,2,3,4}
    new int[ ] {1,2,3,4}
    new elementType[ ]{ }
    Arrays.equals(arrs1,arrs2) 判断数组对象相等(字段全相等)
  • 依赖 uses-a
    聚合 has-a
    继承 is-a
  • jdeprscan 工具类(检测代码中是否使用用已经废弃的API)
  • Objects.requireNonNullElse(n,”unknow”)
    Objects.requireNonNull(n,”The name cannot be null”)
  • 值传递、引用传递
    Java:对象引用是按照值传递的
  • SELECT DISTINCT vend_id FROM products
  • DESC关键字只应用到直接位于其前面的列名
    SELECT prod_id, prod_prrice, prod_name FROM products ORDER BY prod_price DESC, prod_name;
  • SQL优先处理AND操作符
  • IN操作符一般比OR操作符清单执行更快
  • cat 1.txt 查看文件内容

ResultFul

restful资源设计
RESTFul设计指南
DDD以及软件架构设计
看看ES的RESTful接口
找个技术栈的restful学习

JDK JRE JVM

JDK:java Develpment Kit java 开发工具

JRE:java Runtime Environment java运行时环境

JVM:java Virtual Machine java 虚拟机