java基础笔记加强
1. List接口以及他的常用实现类
1.1 List接口
有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。
- ```java
public interface Listextends Collection 1
2
3
4
5
6
7
#### 1.2 `ArrayList`
继承自 `AbstractList`,实现了 List 接口。底层基于数组实现容量大小动态变化。允许 null 的存在。同时还实现了 `RandomAccess`、`Cloneable`、`Serializable` 接口,所以`ArrayList` 是支持快速访问、复制、序列化的。
```java
List<Integer> list = new ArrayList<>();//实现类
1.3 常用方法
- |
boolean
|add(E e)
将指定的元素追加到此列表的末尾。 |
| :—————-: | :—————————————————————————————: |
|void
|add(int index, E element)
在此列表中的指定位置插入指定的元素。 |
|void
|clear()
从列表中删除所有元素。 |
|E
|get(int index)
返回此列表中指定位置的元素。 |
|Iterator<E>
|iterator()
以正确的顺序返回该列表中的元素的迭代器。 |
|E
|remove(int index)
删除该列表中指定位置的元素。 |
|int
|size()
返回此列表中的元素数。 |
|Object[]
|toArray()
以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。 |
1.4 底层实现
ArrayList
底层是基于数组来实现容量大小动态变化的。默认初始容量大小为 10。是线程不同步的扩容:第一次扩容10,以后每次都扩容原容量的1.5倍,扩容通过位运算右移动1位。
```java
Listlist = new ArrayList<>();//实现类
/**- Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
1
2
3
4
5
6
7
8
9
10
11
- 遍历方式:for循环,增强for, 迭代器。
#### 1.5 `LinkedList`
`LinkedList`: `LinkedList` 实现 List 接口,能对它进行[队列](https://so.csdn.net/so/search?q=队列&spm=1001.2101.3001.7020)操作。`LinkedList` 是通过双向链表去实现的。
- ```java
List<Integer> list = new LinkedList<>();//实现类
//栈(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。
//队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。- Default initial capacity.
1.6 面试题:ArrayList
和LinkedList
的区别?
都是线程不同步的。
ArrayList
:
- 基于动态数组的数据结构
- 对于随机访问的get和set,其效率优于
LinkedList
- 对于随机操作的add和remove,
ArrayList
不一定比LinkedList
慢(ArrayList
底层由于是动态数组,因此并不是每一次add和remove都需要创建新数组)
LinkedList
基于链表的数据结构
对于顺序操作,
LinkedList
不一定比ArrayList
慢对于随机操作,
LinkedList
效率明显低于LinkedList
内部是基于链表结构实现的。添加和删除比较快,查询相对
ArrayList
比较慢.内部相对于
ArrayList
而言多了一些操作头和尾的方法。可以充当队列,堆栈。不是线程安全的(同步的)。
2.HashSet
和TreeSet
- 都实现了Set接口,集合中存储的元素不重复。
- 都是无序的
2.1 HashSet
实现原理
- 此类实现
Set
接口,由哈希表(实际为HashMap
实例)支持。 对集合的迭代次序不作任何保证; 特别是,它不能保证订单在一段时间内保持不变。 这个类允许null
元素。 - 去重:根据判断每个元素的
hashCode
值是否相同和equals是否为true判断此元素是否相同 - 如果两个对象的
hashCode
相等 并且 两个对象调用equals结果是true 才认为两个元素重复
2.2 TreeSet
实现原理
- ```java
TreeSetset = new TreeSet<>();
//构造方法
TreeSet(Comparator<? super E> comparator) //构造一个新的,空的树集,根据指定的比较器进行排序。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 介绍:1.无序:不保证(不记录)我们的添加顺序;
2.不重复:不能够添加重复元素
3.内部存储有一定的顺序
***\*注意:`TreeSet`一旦添加了第一个元素后就不能添加其它数据类型的元素了,只能添加相同数据类型的元素,除非将容器中所有的元素全部清空,才能添加新的数据类型的元素\****
- 自然排序:实现Comparable接口,重写此方法,返回值为0表示元素相同,负整和正整数数表示倒序或顺序。
```java
@Override
public int compareTo(Object o) {
//自定义逻辑
return 0;
}
定制排序:实现Comparator(比较器)接口,重写此方法,返回值为0表示元素相同,负整和正整数数表示倒序或顺序。
1 |
|
1 | public class MyComparator implements Comparator{ |
3. IO流
3.1 InputStream
1 | InputStream in = new FileInputStream(File file); |
3.2 FileReader
- 字符输入流一般用于读取文字
1 | FileReader reader=new FileReader(File file); |
3.3 OutputStream
字节输出流写出文件一般用于图片,视频等文件
```java
OutputStream out = new FileOutputStream (File file);
OutputStream out = new FileOutputStream (String pathname);
//缓冲流
BufferedOutputStream buff = new BufferedOutputStream(out);1
2
3
4
5
6
7
8
9
10
#### 3.4 `FileWriter`
- 字符输出流一般用于写出文字
- ```java
FileWriter writer=new FileWriter(File file);
FileWriter writer=new FileWriter(String pathname);
//字符缓冲输出流
BufferedWriter buff = new BufferedWriter(writer);
3.5 复制文件案例
1 | package com.lqs.ioTest; |
3.6 RandomAccessFile
随机访问流读写文件,一般用于下载文件。
|
void
|setLength(long newLength)
设置此文件的长度。 |
| :——: | :—————————————————————————————: |
|void
|seek(long pos)
设置文件指针偏移,从该文件的开头测量,发生下一次读取或写入。 |```java
/**随机访问流读取文件
*/
public class RandomStreamTest {
public static void main(String[] args) throws Exception {String thisLine = null; RandomAccessFile as = new RandomAccessFile("E:\\javabase\\practiceDemo\\src\\com\\lqs\\ioTest\\song.txt", "rw"); System.out.println(as.length()); int count; byte[] bytes = new byte[1024]; while ((count = as.read(bytes, 0, bytes.length)) != -1) { System.out.print(new String(bytes, 0, count)); } as.setLength(1024 * 1024 * 8);//设置文件大小为8M as.seek(1024);//设置偏移量
/* while ((thisLine = as.readLine()) != null) {
System.out.println(thisLine); }*/
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
### 4. 自定义日期转换工具类
```java
package com.lqs.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@SuppressWarnings("all")
public class DateUtils {
/**
* 字符转日期
*
* @param s
* @return
*/
public static Date stringToDate(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
Date date = null;
try {
date = sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**
* 日期转字符
* @param date
* @return
*/
public static String dateToString(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
String s = null;
s = sdf.format(date);
return s;
}
}
5. 设计模式
5.1 单例设计模式
- 单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
- 单例特征:①对象构造私有化,②私有静态当前类类型的字段,③提供公共,静态对外的访问方法获取对象
5.2 饿汉模式
实质上就是在类加载的时候即创建,
饿汉模式线程安全,但是存在加载效率低下的问题,
使用静态内部类块优化。
```java
/**- 单例设计模式
- 1.构造方法私有化
2.初始化成员属性
*/
public class SingleInstance {
private static SingleInstance instance = new SingleInstance();//饿汉单例模式private SingleInstance() {
}public static SingleInstance getInstance() {
return instance;
}
1
2
3
4
5
6
7
8
9
10
11
- ```java
/**
* 饿汉单例模式
* 一开始就初始化对象
*/
@Test
public void testInstance() {//同一个对象
System.out.println(SingleInstance.getInstance());
System.out.println(SingleInstance.getInstance());
}
5.3 懒汉模式
即在需要的时候才创建对象返回,懒汉模式容易造成线程不安全问题,故可以同步代码块【synchronized】解决线程问题,但要使用双重校验,而且同步代码块这种方式效率比较低。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32package com.lqs.utils;
/**
* 单例设计模式
* 1.构造方法私有化
* 2.初始化成员属性
*/
public class SingleInstance2 {
//volatile 保证AB线程会看到变量instance的同一个值
private static volatile SingleInstance2 instance = null;//懒汉单例模式 会出现线程安全问题 需要解决
private SingleInstance2() {
}
public static SingleInstance2 getInstance() {
if (instance == null) {//防止多线程排队
synchronized (SingleInstance2.class) {//同步锁 线程进来需要排队 但是每一个线程进来都需要进行判断导致访问缓慢所以要-->防止多线程排队
if (instance == null) {//防止多个线程排队造成 对象重复创建
//睡眠 会出现线程安全问题
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new SingleInstance2();
}
}
}
return instance;
}
}测试:
1
2
3
4
5
6
7
8public static void main(String[] args) {
System.out.println("=======线程安全问题========");
new Thread(() -> {
System.out.println(SingleInstance2.getInstance());
}).start();
new Thread(() -> System.out.println(SingleInstance2.getInstance())).start();//同一对象
new Thread(() -> System.out.println(SingleInstance2.getInstance())).start();
}
5.3 枚举单例模式(推荐)
```java
package com.lqs.utils;public enum MyEnum {
MAN,//表示一个对象 WOMAN; public void show() { System.out.println("枚举单例设计模式,设计安全哦"); }
}
1
2
3
4
5
6
7
8
9
- 调用:
```java
@Test
public void testEnum() {
MyEnum.MAN.show();//枚举单例设计模式,设计安全哦
System.out.println(MyEnum.WOMAN);//WOMAN
}
5.3 装饰者模式
- 装饰模式指的是在不必改变原类文件和不使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
- 实现步骤 :通过对原类文件继承,对原有方法功能的基础上,实现新的功能.
5.4 简单工厂模式
- 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。(spring反射)
- 实现步骤:使用工厂对象,根据传递的参数创建对象 解耦(耦合)\低耦合高内聚**。
5.5 适配器模式
- 适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
6. 资源文件解析
6.1 概诉
资源文件也可以看成是配置文件,一般的形式有两种:properties形式和XML形式。
properties文件中数据的存储是\以键值对的形式存在,每一行为一条数据,只能存储字符串形式的数据,Properties文件中值的部分任意字符都会被当做值的一部分,尤其是空格**
6.2 Properties类语法
①
load
(字节输入流) 加载资源文件②
getProperty(key)
返回资源文件中对应key中的值【字符串】,若key不存在则返回null③
getProperty(key,默认值)
返回资源文件中对应key中的值【字符串】,若key不存在则返回默认值传统IO方式:
1
2Properties properties = new Properties();
properties.load(new FileInputStream(文件路径));
6.3 类加载器获取流
通过类加载器获取流,那么首要是获取到类加载器,获取类加载器的方式有很多种,以下介绍两种:
字节码对象方式获取类加载器—>>字节码对象
.getClassLoader()
线程方式获取类加载器—>>线程方式获取类加载器稍微比字节码对象获取类加载器稍显复杂,必须先获取当前线程,通过当前线程获取类加载器
Thread.currentThread().getContextClassLoader()
- 获取流语法:类加载器对象
.getResourceAsStream(包名/文件名)
,类加载器获取流的时候,路径最前方不需要书写/
6.4 代码案例
1 |
|
7. 注解
7.1 jdk
四大内置注解
@Override
- 作用:检查方法是否方法覆写
- 位置:方法@Deprecated
@Deprecated
作用:用来标记过时,过时不是不可以用,只是不建议使用
过时:后面的版本可能不维护升级,已经有更好的替换方案
@SuppressWarings
- 作用:抑制警告,不建议使用,注解可以传值
@SuppressWarings("all")
@SafeVarargs
作用:抑制堆污染警告,这个注解是后面才出来的,以前也是使用
@SuppressWarings
解决警告问题堆污染 :不建议使用
7.2 元注解:用来定义注解的注解
- @Target
- 用来定义【注解】的使用位置
- @Retention
- 用来定义【注解】生命周期
- 白话:@Retention 标注在@Override ,Override这个注解的声明周期属于哪个阶段
RetentionPolicy
- SOURCE:源码阶段,编译为字节码以后 注解就不存在了
- CLASS:字节码阶段,运行注解就不存在了
- RUNTIME:运行时,一直存在
- @Documented
- 所标注的【注解】在生成文档以后,在文档中体现出来
- @Inherited
- 所标注的【注解】具有继承性
- 例如 :
- 定义了一个注解
@VIP
,在定义@VIP
的时候使用了@Inherited注解 @VIP
class A{}
class B extends A{}
- B这个类也能继承
@VIP
这个注解
7.3 注解的传值
注解的传值:@注解名字(属性名=值,属性名=值)。
特殊情况:
- 如果属性有默认值,在使用注解的时候可以不用传值【如果没有默认值,必须传值】
- 如果只传一个值,并且属性的名字叫做value,属性名可以省略不写
- 数组的传值 属性名={值1,值2,值3,…}
```java
package com.lqs.reflect;import com.lqs.examination.TransRecord;
@Deprecated//表示类过期了不建议使用
@VIP(number = “00001”, order = {1, 2, 3, 4, 5, 6, 7, 8, 9}, value = “hello”)
public class Person {@Deprecated private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Deprecated @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4. ```java
package com.lqs.reflect;
import java.lang.annotation.*;
//使用范围
//是否生成文档
//生命周期
//注解的继承
public VIP {
String value();
//定义属性
String name() default "coderyeah";
String number() default "1001";
int[] order();//数组
}
8. 反射
8.1 概念
一个Class对象就是表示一个class文件,获取Class对象不能通过new的方式,因为只有java
源程序编译后生成字节码文件,再通过class文件得到Class对象。
会产生class文件的类型有:类,接口,枚举,注解
获取Class对象:
对象.getClass()
Object提供Class.forName(String className)
Class 提供类名.class
8.2 获取Class对象
```java
package com.lqs.reflect;public class User {
private String name; public Long id; private String password; public void eat(String name) { System.out.println(name + "想吃大闸蟹······"); } private void show(String name, int age) { System.out.println(name + "今年" + age + "岁啦"); } //构造器开始 public User() { } private User(String name, Long id, String password) { this.name = name; this.id = id; this.password = password; } //构造器开始 public User(String name) { this.name = name; } //构造器结束
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", password='" + password + '\'' +
'}';
}
}
1 |
|
获取构造器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void testGetConstructor() throws Exception {
final Class<?> cla = Class.forName("com.lqs.reflect.User");
final Constructor<?>[] cons = cla.getConstructors();//获取所有的public修饰的构造器
for (Constructor<?> c : cons) {
// System.out.println(c);//public com.lqs.reflect.User(java.lang.String),public com.lqs.reflect.User()
}
final Constructor<?>[] constructors = cla.getDeclaredConstructors();//获取User中所有的构造器
for (Constructor<?> constructor : constructors) {
// System.out.println(constructor);//包括私有的构造方法
}
//获取指定参数类型的公共构造器
System.out.println(cla.getConstructor());//public com.lqs.reflect.User()
System.out.println(cla.getConstructor(String.class));//public com.lqs.reflect.User(java.lang.String)
//获取指定参数的私有构造器 private com.lqs.reflect.User(java.lang.String,java.lang.Long,java.lang.String)
System.out.println(cla.getDeclaredConstructor(String.class, Long.class, String.class));
}使用构造方法创建对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void testNewInstance() throws Exception {//使用构造方法创建对象
Class<?> cla = Class.forName("com.lqs.reflect.User");
Object newInstance = cla.newInstance();//默认使用无参构造
System.out.println(newInstance);//User{name='null', id=null, password='null'}
//私有构造方法
Constructor<?> constructor = cla.getDeclaredConstructor(String.class, Long.class, String.class);
constructor.setAccessible(true);//让权限检查失效
Object o = constructor.newInstance("coderyeah", 10001l, "root");
System.out.println(o);//User{name='coderyeah', id=10001, password='root'}
//公共构造方法
final Constructor<?> con = cla.getConstructor(String.class);
System.out.println(con.newInstance("山姆"));//User{name='山姆', id=null, password='null'}
}
8.4 使用反射获取方法并调用
获取方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void testGetMethod() throws Exception {
final Class<?> cla = Class.forName("com.lqs.reflect.User");
final Method[] methods = cla.getMethods();//获取所有公共的方法,包括父类所继承的方法
// System.out.println(methods.length);//16
for (Method m : methods) {
// System.out.println(m);
}
final Method[] declaredMethods = cla.getDeclaredMethods();//获取User类所有的方法,不包括父类所继承的方法
// System.out.println(declaredMethods.length);//9
for (Method method : declaredMethods) {
// System.out.println(method);
}
//获取公共的指定方法名和参数类型的方法
//public void com.lqs.reflect.User.eat(java.lang.String)
System.out.println(cla.getMethod("eat", String.class));
/*
获取私有的指定方法名和参数类型的方法
private void com.lqs.reflect.User.show(java.lang.String,int)
*/
System.out.println(cla.getDeclaredMethod("show", String.class, int.class));
}获取方法并调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* 获取方法并调用:
* Method
* Object invoke(Object obj, Object... args) 执行方法
* obj:调用方法的对象
* args:调用方法的实参
*/
public void testInvoke() throws Exception {
final Class<?> cla = Class.forName("com.lqs.reflect.User");
final Method method = cla.getMethod("eat", String.class);
method.invoke(cla.newInstance(), "coderyeah");//coderyeah想吃大闸蟹······
//调用私有方法
final Method show = cla.getDeclaredMethod("show", String.class, int.class);
show.setAccessible(true);//让权限检查失效
show.invoke(cla.newInstance(), "coderyeah", 21);//coderyeah今年21岁啦
System.out.println(cla.getModifiers());//1 public
System.out.println(show.getModifiers());//2 private
}
8.5获取字段并赋值
获取字段并赋值
Field getField(String name)
返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。Field[] getFields()
返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。Field getDeclaredField(String name)
返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。Field[] getDeclaredFields()
返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
```java
package com.lqs.reflect;import org.junit.Test;
import java.lang.reflect.Field;
public class FieldTest {
@Test public void testGetField() throws Exception { final Class<?> cla = Class.forName("com.lqs.reflect.User"); final Field name = cla.getDeclaredField("name"); System.out.println(name);//private java.lang.String com.lqs.reflect.User.name System.out.println(cla.getField("id"));//public java.lang.Long com.lqs.reflect.User.id for (Field field : cla.getFields()) { System.out.println(field);//public java.lang.Long com.lqs.reflect.User.id } /** * private java.lang.String com.lqs.reflect.User.name * public java.lang.Long com.lqs.reflect.User.id * private java.lang.String com.lqs.reflect.User.password */ for (Field field : cla.getDeclaredFields()) { System.out.println(field); } } @Test public void Test2() throws Exception { final Class<?> cla = Class.forName("com.lqs.reflect.User"); final Field id = cla.getField("id"); final User user = new User(); id.set(user, 110L); System.out.println(id.get(user));//110 final Field name = cla.getDeclaredField("name"); name.setAccessible(true); name.set(user, "coderyeah"); System.out.println(name.get(user));//coderyeah }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#### 8.6 使用反射创建任意对象
1. ```java
package com.lqs.reflect;
public class BeanFactory {
public static Object CreateBean(String cla) throws Exception {
final Class<?> aClass = Class.forName(cla);
return aClass.newInstance();
}
public static <T> T CreateBean(Class<T> cla) throws Exception {
return cla.newInstance();
}
}
@Test public void testBean() throws Exception { final Object o = BeanFactory.CreateBean("com.lqs.reflect.User"); System.out.println(o);//User{name='null', id=null, password='null'} System.out.println(BeanFactory.CreateBean(Student.class));//com.lqs.reflect.Student@ba8a1dc }