大家好,又见面了,我是你们的朋友全栈君。
目录
第4章 对象和类
<1>静态字段和静态方法
class Employee{
private static int nextId= 1;
private int id;
....
}
每一个Employee对象都有一个自己的id字段,但是这个类的所有实例将共享一个nextId字段,换句话说,如果有1000个Employee类对象,则有1000个实例字段id,分别对应一个对象,但是只有一个静态字段nextId,即使没有Employee对象,静态字段nextId也存在,它属于类,而不属于任何单个的对象。
<2>初始化块
class Employee{
private static int nextId;
private int id;
//对象初始化块
{
id = nextId;
nextId++;
}
}
<3>定义抽象类的对象变量
但是这样一个变量只能引用非抽象对象
//p是一个抽象类型Person的变量
Person p = new Student("wang wu","zhao si");
<4>hashCode方法得到散列码
散列码是由对象导出的一个整型值,散列码是没有规律的,如果x和y是两个不同的对象,x.hashCode()和y.hashCode基本上不会相同
由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值由对象存储地址得出
var s = "OK";
var sb = new StringBuilder(s);
System.out.println(s.hashCode()+" "+sb.hashCode());
var t = new String("OK");
var tb = new StringBuilder(t);
System.out.println(t.hashCode()+" "+tb.hashCode());
//输出
对象 散列码
s 2556
sb 20526976
t 2556
tb 20527114
注意:1、重写equals方法时一定要重写hashCode方法
2、重写toString()方法是也需要重写hasCode方法
<5>虚拟机中的泛型类型信息
Java泛型的突出特征之一是在虚拟机中擦除泛型类型
第五章 继承
1、Class类
在程序运行期间,Java运行时系统始终为所有对象维护一个运行时类型。
Object类中的getClass()方法将会返回一个Class类型的实例
Employee e;
Class cl = e.getClass();
//获取类的名称,输出 (包路径).Employee
e.getClass().getName();
//对象的名称,输出 Employee类中字段为name的值
e.getName();
使用静态方法forName获得类名对应的Class对象
String className = "java.util.Random";
Class cl = Class.forName(className);
虚拟机位每一个类型管理一个唯一的Class对象。因此,可以利用 == 运算符实现两个对象的比较
if(e.getClass() == Employee.class)….
结果是相等的
getComponentType方法的使用
List<String> list = new ArrayList();
Class cl = list.getClass();
//获取数组的泛型类型,String
Class componentType = cl.getComponentType();
//创建新的数组
Object newArray = Array.newInstance(componentType,10);
建议:
不要滥用反射
反射机制使人们可以在运行时查看字段和方法,从而能编写出更具通用性代码程序。这种功能对于编写系统程序极其有用,但是同程不适于编写应用程序。反射是很脆弱的,如果使用反射,编译器将无法帮助你查找错误,因为只有运行时才会返现错误并导致异常。
第6章.接口、Lambda表达式与内部类
代理是一种非常专业的构造工具,可以用来构建系统系统的工具
Arrays类中的sort方法承诺可以对对象数组进行排序,但要求满足下面这个条件,对象所属的类必须实现Compare接口
假设希望使用Arrays类的sort方法对Employee对象数组进行排序,Employee类就必须实现Compare接口。
public compareTo(Object otherObject){
Employee other =(Employee)otherObject;
return Double.compare(salary,other.salary);
}
第7章 异常、断言和日志
<1>捕获多个异常
try{
//....
}
catch(FileNotFoundException | UnknownHostException e){
//....
}
catch(IOException e){
//....
}
//只有当捕获的异常类型彼此之间不存在子类关系时才需要这个特性
<2> try-with-resource机制
首先被自动关闭的资源需要实现Closeable或者AutoCloseable接口,因为只有实现了这两个接口才可以自动调用close()方法去自动关闭资源。写法为try(){}catch(){},将要关闭的外部资源在try()中创建,catch()捕获处理异常。其实try-with-resource机制是一种语法糖,其底层实现原理仍然是try{}catch(){}finally{}写法
public static void main(String[] args){
try(FileInputStream inputStream = new FileInputStream(new File("test"))){
System.out.println(inputStream.read());
}
catch(IOException e){
throw new RuntimeExption(e.getMessage(),e)
}
}
第9章 集合
<1> 集合接口和实现分离
队里通常有两种实现方式,一种使用循环数组,另一种是使用链表
循环数组是一个有界集合,即容量有限。如果程序中收集的对象数量没有上限,就最好使用链表实现
如果需要一个循环数组队列,可以使用ArrayDeque类,如果需要一个链表队列,就直接使用LinkedList类,这个类实现了Queue接口
<2> 迭代器
用foreach循环可以更加简练地表示同样的循环操作
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iterator.next();
}
<3>集Set
Set接口等同于Collection接口,Set的add方法不允许添加重复的元素
<4>链表
数组和数组列表所有一个重大的缺陷,就是从数组中删除一个元素开销很大,其原因是数组中位于被删除元素之后的所有元素都要向数组的前端移动。在数组中间插入一个元素也是如此。
<5>队列与双端队列
队列允许你搞笑地在尾部添加元素,并在头部删除元素。双端队列允许在头部和尾部高效的添加和删除元素。
boolean offerFirst(E elemnt);
boolean offerLast(E element);
将给定的对象添加到双端队列的对头和队尾,如果队列满了,不会报异常
E pollFirst();
E pollLast();
删除并返回双端队列的元素,如果队列为空,不会报异常
E peekFirst();
E peekLast();
返回双端队列对头的元素,但不删除
<6>优先队列
优先队列(priority queue) 中的元素可以按照任意的顺序插入,但会按照有序的顺序进行检索。也就是说,无论何时调用remove方法,总会获得当前队列中最小的元素,不过,优先队列并没有对所有元素进行排序。
<7>堆
堆是一个可以自己组织的二叉树,其添加和删除操作可以让最小的元素移动到根,而不必花费时间对元素进行排序。
<8>Map
orgListMap.forEach((k,v)->{
//....
});
替换成
for (Map.Entry<Integer, List<String>> mapItem : orgListMap.entrySet()) {
///....
}
<9>枚举集合映射
EnumSet
<10>Collections.synchronizedMap
Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理)
可以多线程访问这个map对象。类似get和put等方法都是同步的,另一个线程才能调用一个方法。
<11>简单算法
Collections.replace(words,”C++”,”java”);
将word列表中为“C++”的值替换成“Java”
<12>批操作
coll1.retainAll(coll2);//从coll1中删除所有未在coll2中出现的元素,求交集
<13>将列表转换为数组
String[] values = staff.toArray(new String[0]);
<14>栈
java.util.Stack
E push (E item);//将item压入栈并返回item
E pop(); //弹出并返回栈顶的item,如果栈为空,不要调用这个方法
E peek();//返回栈顶元素,但不弹出,如果栈为空,不要调用这个方法
<15>属性映射
property map是一个特殊类型的映射结构,
- 键和值都是字符串
- 这个映射可以容易地保存到文件以及文件加载
- 有一个二级表存放默认值
第12章 并发
void join(long mills);
等待指定的线程终止或者等待经过的毫秒数
中断线程
当线程的run方法执行方法中的最后一条语句再执行return语句返回时,或者出现了方法中没有捕获的异常时,线程将终止。
重入锁
ReentrantLock()//构建一个重入锁,可以用来保护临界区
ReentrabtLock( boolean fair);//构造一个采用公平策略的锁。一个公平锁倾向于等待时间最长的线程。不过,这种公平锁保证可能严重影响性能,所以,默认情况下,不要求是公平的。
条件对象
Condition condition;//创建条件对象
condition.await();//当前线程暂停,并放弃锁,这就允许了另一个线程执行。
condition.signalAll();//这个调用会重新激活等待这个条件的所有线程,当这些线程从等待集中移出时,他们再次成为可运行的线程,调度器最终再次将他们激活。
注意:
signalAll调用不会立即激活一个等待的线程。它只会解除等待线程的阻塞,使这些线程可以在当前线程释放之后再竞争访问对象。signal方法只是随机地选择等待集合的一个线程,并解除这个线程的阻塞。
同步块
每个Java对象都有一个锁,线程可以通过同步方法获得锁,还有另一种机制可以获得锁,即进入一个同步块。
synchronized(obj){
//....
}
并行数组算法
Arrays.paralleSort(words,Comparator.comparing(String::length));
任务和线程池
当run方法退出时,这个线程不会死亡,而是留在线程池中准备下一个请求提供服务
Executor中的BlockingQueue的作用:
如果提交的任务数多余空闲线程数,就把未得到的服务的任务放到队列中,当其他任务完成后再提交运行这些排队的任务。
进程 Process
Process process = new ProcessBuilder("/bin/ls","-l")
.directory(Path.of("/tmp").toFile())
.start();
try(var in = new Scanner(process.getInputStream()){
while(in.hasNextLine()){
System.out.println(in.nrxtLine());
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/157049.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...