Java
前言
由于面临找工作困境,结合大环境和自身分析,暂定目标岗位为java后端开发,因此快速学习一下java基础语法。
基础语法
- 数据类型包括基本数据类型和引用数据类型,强制转换使用小括号
- 引用数据类型就是可以被引用的数据类型,包括字符串、
面对对象
内存
- Java中的存储空间,栈中间储存函数和变量,堆中储存对象,元空间储存类的信息。
- 堆中保存的是实例对象的成员属性,元空间中储存的是类的静态属性。
- 先有类再有对象,因此成员函数中可以调用静态函数,但是静态函数不允许调用成员函数
- 类的信息加载完成后,会自动调用静态代码块,可以完成静态属性的初始化功能
包
- 包,容纳类,主要用于功能分类,包含上下级关系
- 创建对象时,可以使用类的相对路径来准确调用
继承与多态
- 继承 Extends
- 类的继承只能单继承,只能有一个父类,不能有多个父类
- super和this 分别表示调用父类的成员变量和子类的成员变量
- 对于一个父类,创建子类n次,那么父类也需要相对应的创建n次,每个不同的子类对应的父类对象不一样
- 多态,一个对象在不同场景下表现出来的不同状态,但是对使用场景进行了约束
重写与重载
- 方法名相同、参数列表不相同,会认为是不同的方法,这就是重载
- 如果子类对象需要在特殊场合使用父类方法,那么就需要重写方法,重写要求子类和父类的方法名字相同,返回值类型相同,参数列表相同。
枚举
- 枚举是特殊的类,包含特定对象,且对象不会改变,使用关键字
enum,对象一般是用大写标识符 - 枚举可以使用构造函数进行构造,枚举类会将对象放置在对前面
- 枚举类不能创建对象,他的对象是在内部自行创建
匿名类
- 匿名类,在一些场合,类的名字不重要,主要是使用类的方法或者功能,因此可以使用匿名类,
- 使用匿名类,减少重复操作,接口也可以使用匿名类,具体实现就是在创建对象的时候直接实现抽象类中的方法即可
- Bean类的设计规范,必须含有无参、公共的构造方法,属性必须私有化,然后提供公共的set、get方法
常见类和对象
Object
toString()默认打印对象的内存地址,输出的是十六进制,也可以使用hashCode(),输出结果十进制equals()判断两个对象是否相等,比较对象的时候,默认比较的是内容地址getSimplename()获取对象的类型信息
数组
- <类型> [] <名称>= new <类型>[size] ;
Boolean类型数组 默认值是false,Object数组和字符串数组默认值是NULLjava中按值传递指的是在调用参数的时候,将实际参数复制一份传递到函数中,这样在函数中对参数进行修改,不会影响到原来的实际参数- 引用传递指的是将实际参数的地址直接传递到函数中,函数对参数的修改会影响原来的实际参数
- 一般来说,对于基础数据类型变量,使用按值传递,对于对象变量,使用的是引用传递。但是实际上二者本质相同,区别就是基础数据类型变量的值是数字和布尔值,而对象引用变量的值是对象的地址。
字符串
字符串是连续的字符组成的整体
字符可以使用
ASCII码来表示字符,ASCII码使用一个字节表示。java使用new构造字符串和直接赋值字符串的方式在底层实现不同。连续的字符数组可以转换为字符串
char cs ={'a','b','b'};
String s = new String(cs);字符串拼接相当于创建新的字符串,并且新的字符串与原来的字符串内存地址不一样。
字符串的比较,采用Object中比较的成员方法
a.equals(b)字符串的截取,
s.substr(straIndex,endIndex),不包含最后的索引字符串的截取,
s.split()字符串的去空格,
s.strim(),去除字符串的首尾空格字符串的替换,
s.replace()或者s.replaceAll()字符串的大小写转换
s.toLowerCase()或者s.toUpperCase()字符串的查找
s.charAt(i);使用
StringBuilder对字符串进行拼接,本质上是使用底层数组完成字符串的拼接StringBuilder s = new StringBuilder();
for(int i=0;i<100;++i){
s.append(i);
}
System.out.println(s.toString());
引用数据类型
- 内置的八种数据类型
byte、short、int、long、float、double、char、boolean并没有对应的属性和方法,因此可以将其进行扩展,使用包装类来实现更多的功能。 - 自动装箱和自动拆箱
- 日期类与日历类的使用
- 工具类不应该创建对象才能使用,这也就意味着可以直接使用类中的属性和方法,一般都声明为静态的
- 工具类对外提供的属性或者方法都应该是公共的
hashcode()主要是获得对象散列地址,并非实际的内存地址,因此hashcode()相等无法证明两个对象为同一个对象,因此使用System.identityHashCode()查看实际的内存地址Integer类中提前将(-128,127)储存到caffe中,因此当数值相同时,即使对象不同,其内存地址也是相等的- 对于引用类型的比较,都需要使用
equals()进行比较,使用==比较的是对象的内存地址
异常
异常分为两类,可以通过代码恢复正常逻辑执行的异常(运行期异常)、不能通过恢复代码恢复的异常(编译器异常),前者是
RuntimeException(),后者是Exception()错误不是异常,是与异常并列的。
Error()异常处理语法,和
swich()比较相似try{
//可能会出现的异常的代码
//如果出现异常,那么JVM会将异常进行封装,形成一个具体的异常类,然后将这个异常抛出
//所有异常对象都可以被抛出
}catch(/*抛出的异常对象,对象引用*/){
//异常的解决方案
}finally{
//最终执行的代码逻辑
}如果方法中可能会出现问题,那么需要提前声明,此时就需要关键字throws。如果需要手动抛出异常对象,那么需要使用throw关键字,然后new出异常
集合
- 集合可以分为单一数据体系和成对出现的数据体系
- Collection接口中常用的子接口包括
List、Set、Queue,其中List的具体实现包括ArrayList和Linked List,Set的具体实现类包括Hashset,Queuen的具体实现类包括ArrayBlockingQueue - Map接口中常用的具体实现包括
HashMap和HashTable
ArrayList
- 增加数据
add(value) - 获取指定位置的数据,采用索引方式
get(index) - 修改指定位置数据
set(index,value) - 删除数据
remove(index) - 扩容机制:
ArrayList底层是数组实现,扩容可以分为两种情况- 当
ArrayList容量是0的时候,此时添加元素需要扩容,不同的构造方法对应不同的扩容策略:- 无参构造,创建
ArrayList后容量为0,添加第一个元素后,容量变为10,此后若需要扩容,则正常扩容。 - 传容量构造,当参数为0时,创建
ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。 - 传列表构造,当列表为空时,创建
ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。
- 无参构造,创建
- 当
ArrayList的容量大于0,并且ArrayList是满的时,此时添加元素的话,进行正常扩容,每次扩容到原来的1.5倍。
- 当
- 插入参数
add(index,value) - 添加集合
add(list) - 获取数据在数据中的索引号
indexOf(value)
LinkedList
- 添加元素
add() - 在头部添加元素
addFirst() - 在尾部添加元素
addLast()
泛型
用于约束外部对象的使用场景,就是类型;用于约束内部对象的使用场景,就是泛型。
泛型基础语法
比较器其实也使用了泛型
public int compare(Integer o1,Integer o2){
// 如果第一个数比第二个数大,那么返回结果为正数,表示升序
return o1-o2;
// 如果第一个数比第二个数小,那么返回结果为负数,表示降序
return o2-o1;
//如果第一个数与第二个数一样大,那么返回零,
return 0;
}
HashSet
- 增加数据
add(value) - 删除数据
remove(value) - 查询数据
set只能遍历查询 - 转换为数组
toArray() - 清空元素
clear() HashSet判断元素不同的标准:HashCode不同,所以即使对象的属性相同,Hashcode不同,HashSet会认为其是两个元素。HashSet底层数据是数组+链表,
Queue
ArrayBlockingQueue数组+阻塞队列- 添加元素
add()当超过容量之后,会直接报错 - 添加元素
put()超过容量之后,会直接堵塞,程序不会继续运行 - 添加元素
offer() - 抛出元素
poll()
HashMap
- 添加数据
put(k,v) - 查询数据
get(k) - 删除数据
remove(k) - 不覆盖添加数据
putIfAbsent(k,v) - 修改数据
replace(k,v) - 获取所有key值
keySet() - 获得所有的value值
values()
HashTable
Table和Map的实现方式不一样;继承的父类不一样,而且Map的(k,v)都可以为空Map的数据定位是哈希算法,Table采用的就是HashCode
迭代器
- 遍历
hashmap时,可以使用迭代器进行遍历,并且进行删除修改操作
问题总结
print数组的时候,直接输出数组得到的是内存地址,可以将其转换为字符串再进行print
IO
File file = new File(path); |
java中对于文件可以自动生成- 缓冲流、字符流、序列化
线程
编译过程
javac指令,生成字节码classJava 程序在运行的时候默认产生一个进程,这个进程会有一个主线程,代码都在主线程中执行
创建线程
//TODO 创建线程
MyTread t = new MyTread();
//TODO 启动线程
t.start();并发:多线程之间彼此独立,互不影响
串行:多个线程连接成线,顺序执行
Tread t1 = new Tread();
Tread t2 = new Tread();
//并发
t1.start();
t2.start();
//串行
t1.join();
t2.join();休眠
Thread.slppe(1000);
快速传递逻辑
Thread T = new Thread(() -> {
System.out.println("逻辑传递");
});
T.start();线程池,就是线程对象的容器,根据需求在启动时可以创建一个或者多个线程对象,Java中常见的线程池包括4种
//TODO 固定数量线程池
//executorService是线程服务对象
ExecutorService executorService = Executors.newFixedThreadPool(3);
//根据需求动态创建线程
ExecutorService executorService = Executors.newCachedThreadPool();
//单一线程,隐含线程顺序
ExecutorService executorService = Executors.newSingleThreadExecutor();
//定时调度线程,可以自定义调度时间
ExecutorService executorService = Executors.newScheduledThreadPool(3)synchronized同步关键字,多个线程访问同步方法的时候,只能一个一个访问,同步操作;修饰代码块,使得代码块成为同步代码块。synchronized具有原子性、可见性和有序性
- 同步理解如下,对于一个对象
x=0,线程A第一次访问时,由于本地内存中没有x,需要将其从主内存缓存到本地内存A中,进行更改x=1,并将其放回到主内存中;线程B第一次访问则将x=1读入本地内容B中,并修改为x=2然后放回主内存中。线程A第二次访问x时,由于本地内存A中存在,则会直接是使用本地内存中x=1,因此会出现内存不可见的问题。 wait()需要等待其他进程释放资源之后,线程才能够继续进行,属于被迫性的阻塞sleep()线程自动的休眠,主动性的阻塞wait()Object类中的成员方法,因此每一个对象都会有wait方法;必须在同步代码块中才能使用;如果执行wait()方法,其他线程可以执行当前的同步操作sleep()Thread类中的静态方法,在任意情况下都可以使用,其他线程不能执行当前的同步操作。java对每一个线程创建一个栈内存,但是对于每一个对象,在堆中开辟新的空间。因此,在多个线程并发执行的时候,修改共享内存中对象的属性,会导致数据冲突问题。
反射
- Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性
结语
由于时间仓促,短暂学习后在读博和工作之间举棋不定,后经深思熟虑,决定专攻学术研究,因此Java语法暂时告一段落。因此本篇难免显得虎头蛇尾,若有机会,小子定会补全(抱拳)



