Dos基础命令
更换盼复:d:
查看当前目录下的文件及文件夹
进入文件夹 cd 文件名字
返回上一级 cd...
清空屏幕:cls
删除文件:del 文件名
删除文件夹: rd 文件夹名字
退出:exit quit
创建文件:copy nul 文件名.文件类型
创建文件夹:mkdir 文件夹名
cmd命令行窗口字符编码切换为UTF-8,命令行中执行:chcp 65001
JAVA 接口文档package包介绍:D:Program FilesJavajdk1.8.0_241jrelib t.jar
一、java概述与环境搭建
- java在1995年有sum Microsystems 推出,经过24年迭代
- JAVA的特点是面向对象、简单、跨平台
- 将源文件编译成字节码文件(.class),在交与不同平台进行解释执行。
- JVM虚拟机、JRE运行环境、JDK开发环境
- DOS 命令 (见开头)
- 开发步骤
a) 创建.java源文件
b) 编写程序(class 、 main 、逻辑代码)
c) 编译:javac 文件名.java (文件名.后缀名)
d) 运行:java 类名(无后缀)
- 同一个源文件中可以定义多个类
- 编译后,每个类都会生成独立的 .class 文件
- 一个类中,只能有一个主函数,每个类都可以有自己的主函数。
- public修饰的类称为公开类,要求类名必须与文件名称完全相同,包括大小写
- 一个源文件,只能有一个public 公开类。
package 包:
作用:类似于文件夹,用于管理字节码(.class)文件。
语法: package 包名;
位置:包名必须写在源文件的第一行
带包编译:javac -d . 源文件名.java
带包运行:java 包名.类名(包名+类名)
采用域名倒置规则:www.baidu.com --> com.baidu.www
二、语言基础:
- 前置知识:
什么是内存:内存是瞬时状态下的存储空间,造价高、工业上的设计瓶颈。
java虚拟机(java程序)默认分配到的物理内存是1/8
bit -> Byte -> KB -> MB -> GB -> TB -> PB -> EB -> ZB -> YB -> BB -> NB -> DB -> CB -> XB
2.变量
变量定义流程:
声明:数据类型 变量名;
赋值: 变量名 = 值
Java中变量具有严格的数据类型区分
在Java语言中,任何一个值,都有其对应类型。
整数类型的取值范围:(默认取值为:int)
浮点类型取值范围:(浮点的默认类型:double)
单精度:float 将小数存入变量中时需在数值尾部加入“F”:float p= 12.51F; 否则将会报编译错误;
近似值:
float 32bit 1bit 符号位 8bits指数位 23bits尾数位
double 64bit 1bit 符号位 11bits指数位 52bits尾数位
布尔类型:
字符类型:
字符转义符: 例; ’ ...
字符串:
类型转化:
同类型转换中,需目标类型大于源类型;
强制类型转换中(大的往小的里放),可能会出现精度丢失,
方法: target a = ( target )b
short num =123;
byte target = (byte)num;
赋值运算:
包定义:明确该文件的.calss文件结构,必须放在文件的首行; package p1;
引入包: import ...
控制台输入:根据输入的内容进行程序的执行。
import java.util.Scanner;
Scanner inputInfo = new Scanner(System.in);
System.out.println("请输入内容:");
int num = inputInfo.nextInt(); // 输入类型为int;
double num = inputInfo.nextDouble();// 输入类型为小数;
String num = inputInfo.next();// 输入类型为串;
char num = inputInfo.next().charAt(0);// 输入类型为字符;
implements 接近于类实现某接口(interface)
定于接口与类的实现:
public interface People{
public void say();
}
public class Chinese implements People{
public void say(){
System.out.print(‘hello’);
}
}
People chinese = new Chinese()
chinese.sya()
与extends的区别,extends 表示对父类的继承,且一个类只可单一继承,可以实现父类,也可调用父类的方法,而且可以重写覆盖父类定义的方法及属性。
implements表示对接口的实现,通过接口关键字‘implements’实现,在接口中声明方法,在子类中实现方法。
当方法需要实现,不可修改,固定为规定的模板时使用implements,只定义接口。而需要被实现,或者可以被修改,拓展性好,用extends ;
函數:
概念:实现特定功能一段代码,可反复使用。
定义语法:
plublic static void FunctionName(String[] args){
}
将需要多次复用的代码,定义在函数中,减少代码量;
函数定义在类的函数内部,与main 相同层级;
数值的比较equals():
在java中,进行字符串类型的对比,因字符串为引用地址类型,对比的数据值为内存地址,所以使用“==”,将无法获得准确的数值,String.equals() 可对应解决字符串数值比对,其内部源码比对的是源对象,与目标对象的字符长度及每一个下标的数值是否相等;
String.contentEquals();其作用与equals相同,但是其内部将会区分StringBuilder 类型,然后进行对比。
a.equals(b);
a.contentEquals(c);
返回值与返回值类型:
函数调用时,一些情况下无需返回结果,另一些情况下则必须返回结果。
定义语法:
public static 返回值类型 函数名称(形式参数列表){
//函数体
return value; //返回值
}
数组的创建语法:
//合并数组方法1
int [] newArr = new int[oldArr.length+newArrList.length];
System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
System.arraycopy(newArrList, 0, newArr, oldArr.length, newArrList.length);
for(int i = 0 ; i <newArr.length;i++) {
System.out.print(newArr[i] +" ");
}
//合并数组方法2
int [] newArr = java.util.Arrays.copyOf(oldArr, oldArr.length+newArrList.length);
System.arraycopy(newArrList, 0, newArr, oldArr.length, newArrList.length);
for(int i = 0 ; i <newArr.length;i++ ) {
System.out.print(newArr[i] + " ");
}
数组的扩容:
Java中数组在声明完长度时候是不可改变原数组的长度的,但可以使用获取原数组的长度,创建新数组时,重新设定新数组的数据内容,并添加新的数据,从而达到数组的扩容功能;
private int[] dilatation(int[] oldArr,int addLenght) {
return java.util.Arrays.copyOf(oldArr, oldArr.length+addLenght);
}
数组的插入Insert: 将数组指定位置以后的值赋予前一个地址,在将指定位置内容进行覆盖。
void insert( int position , int data ) {
if(stack.length == size) {
stack = dilatation(stack,1);
}
for(int i = size;i > position ; i --) {
stack[i] = stack[i-1];
}
stack[position] = data;
size++;
}
可变长参数:
概念:可接受多个同类实参,个数不限,使用方式与数组相同。
语法:数据类型: ... 形参名 必须放在参数列表最后,且只能存在一个。
传入参数与python 方法类似,默认除开形参个数以外的内容,整合封装到... arr 之中。
数组的排序:
冒泡排序:相邻的两个数值比较大小,之后进行位置的互换
java.util.Arrays.sort(arr); JDK排序
二维数组创建语法
先声明,在分配空间:
数组类型[][] 数组名;
数组名 = new 数据类型[高维长度][低维长度];
声明并分配空间:
数据类型[][] 数据名 = new 数据类型 [高维长度][低维长度];
声明并赋值:
数据类型[][] 数据名 = new 数据类型[高维长度][]; //不规则数组,自行new 低维数组;
声明并赋值:
数据类型[] 数据名 = {{v1,v2,v3},{v4,v5,v6},{v7,v8,v9}};
double 类型保留2位小数:
String.format(“%.2f”,f);
DecimalFormat df = new DecimalFormat("#0.00") df.format(f)
NumberFormat nf = NumberFormat.getNumberInstance(); nf.format(f))
DoubleFormat f = new DoubleFormat(); f.m1()
杨辉三角:
public static int[][] yhArr(int rows ) {
// 1
// 1 1
// 1 2 1
// 1 3 3 1
// 1 4 6 4 1
// 1 5 10 10 5 1
int[][] arr = new int[rows][];
for(int i = 0 ; i < rows ;i++ ) {
arr[i] = new int [i+1];
for (int j = 0 ; j <= i ; j++) {
arr[i][j]= (j>0 && i >1 && j!=i)?arr[i-1][j] + arr[i-1][j-1]:1;
}
}
return arr;
}
方法的重载
方法重载(overload)是指方法名称相同,但是形参列表不同(参数类型、参数个数、参数顺序)的方法。调用重载的方法时,Java编译器会根据实参列表寻找最匹配的方法进行调用。
面向对象的思想里,方法重载就是对象的另一种行为存在多种实现过程,就构成了方法重载。
在面向对象中,我们还需要学习到方法(覆盖)override。
对象与类:
程序中的对象:
类的定义:
属性:通过变量表示,又称实例变量。
语法:数据类型 属性名;
位置: 类的内部,方法的外部。
方法:通过函数的表示,又称为实例方法。
语法:
public 返回值类型 方法名(形参){
//方法的主体
}
类与对象的关系:
Extends继承中子类的super:
this与super:
this在java中指向当前实例,当调用this()是指向的是当前类的super() (只可在无参情况)
super 指向父类实例;
多态:
概念:父类引用产生多种形态,从而产生多态;
将子类对象当成父类类别看待;
在子类方法覆盖父类方法之后 ,在父类参数中调用被覆盖的方法时 将自动调用子类方法
使用父类作为方法形参实现多态,使方法的参数的类型更加广泛。
使用父类作为方法的返回值实现多态,使方法可以返回不同子类对象。
向上转型(装箱)
父类引用中保留真实子类对象,称为向上转型(即多态核心概念)
Animal pet = new Dog()
想下转型(拆箱)
将父类引用中的真是子类对象,强转回子类本身类型,称为向下转型。
注意:只有转回子类真是类型,才可以调用子类独有的属性和方法。
Dogs pet = (Dog)pet;
判断目标是否是某个类的实例,从而进行对应的拆箱:
pet instanceof Dogs
个人理解:多态也可以理解为多样,在将父类作为参数或者返回值时,根据类的继承关系,在调用父类时,指向的还是原子类对相关,即父类引用指向子类对象。
总结复习
父类的抽象:
程序中的继承:
程序中的继承,是类与类之间的特征和行为的赠与或获得。
两个类之间的继承关系,必须满足“is a”的关系。
java为单继承,一个类只能有一个直接父类,但可以多层继承,属性和方法逐级叠加。
不可继承:
访问修饰符:
方法的覆盖:
覆盖原则:
super 关键字:
super 、 this访问属性:
super调用父类有参构造
this与super
程序的多态:
多态中的方法覆盖:
多态的应用:
类型转换异常:
instanceof关键字:
get/set方法编写:
关键字:
abstract 抽象
什么是抽象:似是而非,像却又不是,具备某种对象的特征,但又不完整。
抽象类:abstract 修饰类,此类不能New对象。
被Abstract修饰的类,称为抽象类。抽象类意为不完整的累、不够具体的累,抽象类对象无法独立存在,即不能new对象。
抽象方法:
抽象类中的抽象方法与interface 接口一样,定义的抽象方法必须要子类全部实现,否则子类就不是完整的实例子类。
总结:
@override 方法的覆盖关键字,指覆盖其父级方法,静态方法不可覆盖。
static 静态:
static 声明,将在全局方法区,共同声明同一个方法或属性,全局共用。
静态方法时可以通过类名调用(在调用该方法时,可能从未创建对象)
JAVA中的方法调用分为两种:
- 静态分派(静态方法中,允许参数列表不同的重名方法,指静态方法之间的重载)
- 动态分派(在具有继承关系的情况下,调用实例方法时,自底向上查找可用的方法版本,指实例方法的覆盖)
方法调用指令5个:
invoke spacial 私有方法、构造方法
invoke interface 接口方法
invoke static 调用静态方法
invoke virtual 调用虚方法()
invoke dynamic 调用动态链接方法
静态方法允许直接访问静态成员
静态方法不能直接访问非静态方法
静态方法中不允许使用this super关键字
静态方法可以继承,不能重写,没有多态。
个人观点为:静态方法属性在初始化时为最优先级,切与其他实例无直接联系,而在动态方法初始完成时,实例方法还未动态生成完成。
编译器可知,运行期不可变。
类加载
JVM首次使用某个类时,需通过CLASSPATH查找该类的 .class文件。
将查找到的class文件,读取其描述信息,存入内容之中
加载时机:
创建对象 创建子类对象 访问静态属性 调用静态方法 Class.forName(“全限定名”);
final
概念:最后的,不可更改的
final可修饰的内容:
类(最终类)
方法(最终方法)
变量(最终变量)
final修饰类:此类不能被继承。
接口的语法:
接口相当于特殊的抽象类,定义的方式、组成部分与抽象类相似。
与抽象类的异同:
相同:
可编译成字节码文件。
不能创建对象。
可以做作为引用类型。
具备Object类中所定义的方法。
不同:
所有属性都是公开静态常量,隐式默认为:public static final 修饰
所有方法都是公开抽象方法,隐式默认为:public abstract 修饰
没有构造方法,公共代码块,静态代码块
什么是接口:
微观概念:接口是一种能力和约定。
接口的定义:代表了某种能力。
方法的定义:能力的具体要求。
抽象方法(规定子类必须存在的行为,规范了其行为的具体要求);
接口是一种能力,接口中的方法就是一种约定。
经验:JAVA为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力。
接口的规范:
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
实现接口中的抽象方法时,访问修饰符必须是public.
接口引用:
同父类引用一样, 接口也可声明为引用,并指向实现类对象。
注意:
仅可调用接口中所声明的方法,不可调用实现类中独有的方法。
可强制转回接口的实现类型,从而调用其原有的属性方法。
接口的多态:
接口引用,指向实例化接口对象,从而实现接口多态。
常见关系:
类与类:
单继承
extends:父类名称
类与接口:
多实现
implements 接口名称1,接口名称2,接口名称N
接口与接口:
多继承 extends
父类接口1,父类接口2,父类接口N
常量接口:
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口统一管理,提高代码可读性。
枚举(规范了取值的类型):关键字 enumerate
enum state{
false,true,or
}
谁去Implements 那就是实现者
谁去new 实现类 那就是使用者
接口的回调:
接口回调:先有接口的使用者,后有接口的实现者
接口的好处
程序的耦合度降低
更自然的使用多态。
设计与实现完全分离。
更容易搭建程序框架。
更容易更换具体实现。
总结:
内部类的分类:
成员内部类、静态内部类、局部内部类、匿名内部类
概念:在一个类内部再定义一个完整的类。
class Outer{
class Inner{
}
}
特点:
编译之后可以生成独立的字节码文件。
内部内可直接访问外部类的私有成员,而不破坏封装。
可谓外部类提供必要的内部功能组件。
成员内部类:
在类的内部定义,与实例变量、实例方法同级别的类。
外部类的一个实例部分,成员内部类依赖外部类对象的实现。
当外类、内部类存在重名属性时,会优先访问内部类属性。
成员内部类无法定义静态成员。
静态内部类:
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
局部内部类:
定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final.
匿名内部类:
Object类
getClass()方法
public final Class<?> getClass(){}
返回引用对象的实际类型
应用:通常用于判断两个引用中的实际存储对象类型是否一致
hashCode()方法
public int hashCode(){}
返回一个该对象的十进制的哈希码值
哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值
哈希码并不是唯一,可保证相同对象返回相同的哈希码,尽量保证不同对象返回不同的哈希码。
toString()方法
public String toString(){}
返回该对象的字符串表现形式
可以根据程序需要覆盖该方法,如展示对象各个属性值。
equals()方法
public boolean queals(Object obj){}
默认实现为(this == obj) , 比较两个对象地址是否相同。
可进行覆盖,比较两个对象的内容是否相同。
equals() 方法的覆盖步骤:
public boolean equals(Student obj){
if(this == obj){
return false ;}
if(obj== null){
return false; }
if(this.getClass() != obj.getClass(){
return false}
if(this.name.equals(s.name) && this.age == s.age &&this.sex.equals(s.sex){
return true}
return false;
}
finalize()方法
当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
垃圾对象:没有有效的引用指向此对象时,为垃圾对象。
垃圾回收:有GC销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc();通知JVM执行垃圾回收。
可达性分析算法
包装类:
什么是包装类?
基本数据类型所对应的引用数据类型
Obect 可统一所有数据,包装类的默认值是null
包装类对应:
类型转换与装箱、拆箱
8种包装类提供不同类型间的转换方式:
Number父类中提供的6中共性方法;floatValue、doubleValue、byteValue....
parseXXX()静态方法;parseInt、parseDouble....
valueOf()静态方法: intValueOf、doubleValueOf....
通过包装累继承得来的XXX ValueOf()方法,进行各类型之间的转换;
注意:需保证类型兼容(取值范围兼容、值类型兼容),否则抛出NumberFormatException异常
整数缓存区:
Java预先创建了256个常用的整数包装类型对象。
在实际应用当中,对已创建的对象进行复用。
String:
字符串为常量,创建之后不可改变。
字符串字面存储在字符串池中,可以共享。
String s = “hello”; 产生一个对象,字符串池中存储。
String s = new String(“Hello”); 产生两个对象,池 与 堆 中各一个。
字符串实际是字符数组的包装类;
常用方法:
string.charAt(0) 通过下标获取字符串字符。
contains(String str): 判断当前字符串中是否包含str。
toCharArray() : 将字符串转换成数组。
indexOf(String str , fromIndex i): 查找str首次出现的下标,存在,返回下标值;不存在返回-1, 第二个参数为从下标i起始查询;
length() :返回串的长度;
trim() :去掉串前后的空格;
toUpperCase():将小写统一转为大写;
toLowerCase():将大写统一转为小写;
str1.equalsIgnoreCases(str2): 忽略大小写判断俩个串内容是否相同;
endsWith() :判断串是否已指定内容结尾;
startsWith() :判断串是否已指定内容开头;
replace():替换新内容;
Substring() :截取指定下标范围的内容;
StringBuffer:构造一个其中不带字符的字符串缓冲区,初始容量为16个字符,运行效率慢、线程安全。
线程安全的可变字符序列。一个类似于String的字符串缓冲区,但不能修改,虽然在任意时间点上他都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
StrintBuffer sb1 = new StringBuffer(“xxx”);
public String toString(); 返回串
StringBuilder:构造一个其中不带字符的字符串缓冲区,初始容量为16个字符,运行效率快、线程不安全。
一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。建议优先采用该类,在多数情况下,StringBuilder更快。
StringBuilder sb2 = new StringBuilder(“xxx”);
StringBuilder与StringBuffer所有API基本相同;只是运行效率不同。
BigDecimal 精确计算
不可变的,任意精度的有符号十进制数。
加:BigDecimal result = bg1.add(bg2);
减:BigDecimal result2 = bg1.subtract(bg2);
乘:BigDecimal result3 = bg1.multiply(bg2);
除:BigDecimal result4 = bg1.divide(bg2, 2,BigDecimal.ROUND_UP);
只有除法精确计算是需要添加保留位数,及取上或取下;
集合
概念:对象的容器,存储对象的对象,可代替数组。
特点:容器的工具类,定义了对多个对象进行操作的常用方法。
位置:java.util.*;
Collection体系集合:
特点:代表一组任意类型的对象,无序、无下标
Collection层次结构中的根接口,Collection表示一组对象,这些对象也可称为Collection的元素,一些collection允许有重复的元素,而另一些则不允许。
方法:
boolean add(Object obj) 添加一个对象
boolean addAll(Collection c) 讲一个集合中的所有对象添加到此集合中
void clear() 清空所有对象
boolean contains(Object o ) 检查此对象是否包含该对象
boolean equals(Obejct o) 比较此集合与指定对象是否相等
boolean isEmpty() 判断此结婚是否为空
boolean remove(Object o) 在此集合中移除o对象
int size() 返回此集合中的元素个数。
Object[] toArray() 将此集合转换为数组。
List 子接口
特点:有序、有下标、元素可重复
说明:有序的collection,此接口的用户可以对列表中每个元素的插入位置进行精确控制。用户可以根据元素的整数索引访问元素,并搜索列表中的元素。
与set不同,列表通常允许元素重复
方法:
List 实现类:
ArrayList 类 :
数据结构实现,查询快、增删慢;
JDK1.2版本,运行效率快,线程不安全。
Vector(使用方法与ArrayList相同,目前暂不建议使用):
数组结构实现,查询快、增删慢;
JDK1.0版本,运行效率慢、线程安全。
LinkedList:
链表结构实现,增删快,查询慢。
linklist接口的链接列表实现,实现所有可选的列表操作,并且允许元素(包括Null),除了实现List接口外,LinkedList类还未列表的开头及结尾get、remove和insert元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
LinkedList 因是队列链式结构,开头与结尾的查询功能效率很高,所以添加了一些对应的方法
list.addFirst()、list.addLast()、list.peekFirst()、list.peekLast()、list.removeFirst()、list.removeLast();
泛型集合:
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点:
编译时即可检查,而非运行时抛出异常。
访问时,不必类型转换(拆箱)。
不同泛型之间引用不能相互赋值,泛型不存在多态。
实例泛型:
如果是泛型类,在创建对象的时候指明泛型类型;
如果是泛型接口,在实现接口的是后指明泛型类型;
静态泛型:
Collections泛型集合
概念:集合工具类,定义了除了存取以外的集合常用方法。
方法:
public static void reverse(List<?> list) 反转集合中的元素顺序
public static void shuffle(List<?> list) 随机重置集合元素的顺序
public static void sort(List<?> list) 升序排序(元素类型必须实现Comparable接口)
Comparable<?> 排序接口 须实现其compareTo方法
Set 集合
特点:无序、无下标、元素不可重复
方法:全部继承自Collection的所有方法
Set的实现类:
HashSet【重点】:
基于HashCode实现元素不重复。
当存入元素的哈希码相同时。会调用equals进行确认,如结果为true,则拒绝后则的存入。
遍历HashSet的方法为foreach循环:
for遍历写法:
for(Student i : list)
System.out.println(i.age);
TreeSet:
基于排列顺序实现元素不重复。
实现了SortedSet接口,对集合元素自动排序。
元素对象的类型必须实现Comparable接口,指定排序顺序
通过CompareTo方法确定是否为重复元素。
使用TreeSet集合时,实现接口Comparable,之后针对性重写compareTo方法,否则排序去重不能达到理想效果。
@Override
public int compareTo(Teacher o) {
// TODO Auto-generated method stub
if(salary > o.salary ) {
return 1;
}else if(salary < o.salary ) {
return -1;
}else {
if(name.compareTo(o.name)>0) {
return 1;
}else if( name.compareTo(o.name)<0) {
return -1;
}else {
return 0;
}
}
}
Map体系集合
map接口的特点:
- 用于存储任意键值对(Key - Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
接口Map<K , V>
public interface Map<K , V> : 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
特点:一对数据(KEY-Value),无序、无下标,键不可重复,值可重复。
方法:
V put(K key , V value) 将对象存入到集合中,关联简直。Key重复则覆盖原值。
Object get(Object key) 根据键值获取对应的值。
Set<K> keySet 返回所有Key内容的set集合。
Collection<V> values() 返回包含所有Value的Collection集合。
Set<Map.Entry<K,V>> entrySet() 键值匹配的Set集合
HashMap【重点】:线程不安全,运行效率快,允许用Null 作为Key 或者value
基于哈希标的Map接口的表现。此实现提供所有可选的映射操作,并与允许使用Null值和null键。(除了非同步和允许使用Null之外,HashMap类与Hashtable大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
方法:listMap.containsKey(str) 查询map中是否有已存在的Key
HashTable:GDK1.0, 线程安全,运行效率慢,不允许使用null 作为key或者value;
Set<String> set = Country.countres.keySet();
Collection<String> values = Country.countres.values();
Set<Entry<String, String>> entry = Country.countres.entrySet();
for(Entry<String, String> i : entry)
System.out.println(i.getKey());
Properties: HashTable的子类,要求Key和value都是String.通常用于配置文件的读取。
Properties properties = new Properties();
properties.setProperty("aaa", "bbbb");
properties.getProperty("aaa");
TreeMap:
实现了SortedMap接口(是MAP的子类),可以对Key自动排序。
Map<String, String> treeMap = new TreeMap<String, String>();
treeMap.put("CN1", "现在的年轻人");
该方法同样存在values() keySet() entrySet() 三个角度试图
总结:
异常
概念:程序在运行过程中出现的特殊情况。
异常处理的必要性:任何程序都可能存在未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中端,造成不必要的损失。
Throwable:可抛出的,一切错误和异常的父类,位于java.lang包内。
Erro: JVM、硬件、执行逻辑错误,不能手动处理。
Exception: 程序在运行和配置中产生的问题,可处理。
RuntimeException:运行时异常,可处理,可不处理。
CheckedEception:受查异常,必须处理。
自动抛出异常:当程序在运行时遇到不符合规范的代码时。
手动抛出异常:语法 throw new 异常类型(“实际参数”);
产生异常结果:相当于遇到return语句,导致程序因异常而终止。
异常的传递:throws 声明异常,修饰符在方法参数列表后端。
受查异常:throws 声明异常,修饰在方法参数列表后端。
运行时异常:行时异常,可处理,可不处理.
try {
s1.setAge(12);
(可能出现的异常代码)
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace(); //打印堆栈中出错的内容
(相关代码的自定义处理方案,如:getMessage()、printStackTrace());
}finally{
(无论是否出现异常,都会执行finally里的语句)
}
自定义异常
需继承自Exception或Exception的子类,常用的RuntimeException.
必要提供的构造方法:
无参数构造方法
String message 有参构造方法
方法覆盖:
带有异常声明的方法覆盖:
方法名、参数列表、返回值类型必须和父类相同。
子类的访问修饰符合父类相同或是比父类更宽。
子类中的方法,不能抛出比父类更多、更宽泛的异常。
总结:
- List:有序集合,元素可重复
- Set:不重复集合,LinkedHashSet按照插入排序,SortedSet可排序,HashSet无序
- Map:键值对集合,存储键、值和之间的映射;Key无序,唯一;value 不要求有序,允许重复
Collections包下的unmodifiableXXX方法,通过这个方法返回的map、List、Set,是不可以修改的
Collections.unmodifiableMap(Map)
Collections.unmodifiableList(List)
Collections.unmodifiableSet(Set)
public static void main(String[] args) {
List<Character> oldList = new ArrayList<Character>();
for (char i = 'A'; i < 'Z'; i++) {
oldList.add(i);
}
List<Character> unChangeList = Collections.unmodifiableList(oldList);
测试过后:调用add、remove方法均会抛出错误java.lang.UnsupportedOperationException
线程
单词: Runnable 可运行 就绪状态 可运行状态 就绪
什么是进程:
什么是线程:
线程的组成:
启用线程的方法:
方法1:
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程1 "+Thread.currentThread().getId()+":"+i+"已开启");
}
}
}
MyThread myThread = new MyThread(null);
myThread.start();
方法2:
class PrimeRun implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; i++) {
System.out.println("线程id: "+Thread.currentThread().getId()+"-"+i+"已开启");
}
}
}
PrimeRun primeRun = new PrimeRun();
PrimeRun p2 = new PrimeRun();
p2.start();
线程的状态(基本)
方法:
休眠: public static void sleep( long millis) 当前线程主动休眠 millis毫秒。
放弃: public static void yield() 当前线程主动放弃时间片,会到就绪状态,竞争下一次时间片。
结合: public final void join() 允许其他线程加入当前线程中,并优先执行。
线程的状态(等待):
线程的安全问题:
需求:A线程将“HELLO”存入数组的第一个空间;B线程将“World”存入数组的第一个空位。
线程不安全:
当多线程并发访问临界资源时,如果破坏原子操作,可能造成数据不一致。
临界资源:共享资源(同一个对象),一次仅允许一个线程使用,才可保证其正确性。
原子操作:不可分隔的多步操作,被视为一个整体,其顺序和步骤不可打乱或缺省。
同步方式(1)
同步代码块:
synchronized(临界资源对象){ //对离临界对象资源加锁
//代码块
}
注:
每个对象都有一个互斥锁标记,用来分配给线程的。
只有拥有对象互斥标记的线程,才能进入对该对象加锁的同步代码块。
线程退出同步代码块时,会释放相应的互斥锁标记。
线程的状态(阻塞)
同步的规则:
线程的通知:
等待:
public final void wait();
public final void wait(long timeout);
必须在堆obj加锁的同步代码块中。在一个线程中,调用obj.wait()时,此线程会释放拥有的所有锁标记。同时此线程处在无限期等待的状态中,释放锁,进入等待队列。
通知:
public final void notify();
public final void notifyAll();
必须在堆obj加锁的同步代码块中,从obj的Waiting中释放一个或全部线程。对自身没有任何影响。
经典问题:
关键字:synchronized 或者同步代码块 synchronized(){///}
总结:
守护线程:thread.setDaemon(true);守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。
通常来说,守护线程经常被用来执行一些后台任务,但是呢,你又希望在程序退出时,或者说 JVM 退出时,线程能够自动关闭,此时,守护线程是你的首选。
Runtime.getRuntime().addShutdownHook(
new Thread(()-> System.out.println("The jvm exit Success!"))
); //查看java虚拟机退出时机
Thread thread = new Thread(()->{//创建线程
while(true) { //不断执行
try {
Thread.sleep(1000);
System.out.println("I am running~~");
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
}) ;
thread.setDaemon(true);//设置守护线程
thread.start();
try {
thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
System.out.println("main thread to exit!"); //打印主线程结束时机
}
线程池概念
现有问题:
线程是宝贵的内存资源、单个线程约1MB空间,过多分配易造成内存溢出。
频繁的创建及销毁线程会增加虚拟机回收效率、资源开销,造成程序性能下降。
线程池:
线程容器,可设定线程分配的数量上限。
将预先创建的线程对象存入池中,并重用线程池中的线程对象。
避免频繁的创建和销毁。
将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程。
获取线程池
常用的线程池接口和类(所在包 java.util.concurrent):
Executor:线程池的顶级接口。
ExecutorService:线程池接口,可通过submit(Runnable task) 提交任务代码。
Executors工厂类:通过此类可以获得一个线程池。
通过newFixedThreadPool(int nThreads) 获取固定数量的线程池。参数:指定线程池中线程的数量。
通过newCachedThreadPool() 获得动态数量的线程池,如不够则创建新的,没有上线。
ExecutorService serve = Executors.newFixedThreadPool(3); //调用固定线程池
ExecutorService serve = Executors.newCachedThreadPool(); //调用缓存线程池
Runnable task = new MyTask(); //生成任务
erve.submit(task); //执行
shutdown();结束所有线程。
isTerminated(); 判断所有线程是否结束;
Callable接口
public interface Callable<V>{
public V call{} throws Exception;
}
JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。
Callable具有泛型返回值、可以声明异常。
Future<V>接口
概念:异步接受ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值。
V 代表future的get方法返回的结果类型,get方法以阻塞形式等待Future中的异步处理结果(call());
Future代表异步计算的结果,他提供了检查是否完成线程,及等待计算结果,并获取计算的结果。
接口实现:
class CallTask implements Callable <Integer>{
@Override
public Integer call() throws Exception {
int value = 1 ;
for(int i = 0 ; i < 10 ; i++ ) {
value += i;
System.out.println("task"+Thread.currentThread().getId()+": "+i);
};
return value;
}
}
调用:
ExecutorService serve = Executors.newCachedThreadPool();
Callable<Integer> task = new CallTask();
Future<Integer> result = serve.submit(task); //返回Future类型结果;
result.get(); //获得返回的结果;
同步:
形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续。
异步:
形容一次方法调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回。二者竞争时间片,并发执行。
Lock接口
JDK5加入,与synchronized比较,显示定义,结构更灵活。
提供更多使用性方法,功能更强大、性能更优越。
常用方法:
void lock() //获取锁,如锁被占用,则等待。
boolean tryLock() //尝试获取锁(成功返回true.失败返回false,不阻塞)
void unlock() //释放锁
重入锁
ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能。
读写锁
ReentrantReadWriteLock:
一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。
支持多次分配读锁,使多个操作可以进行。
互斥规则:
写-写:互斥,阻塞。
读-写:互斥,读阻塞写、写阻塞读。
读-读:不互斥、不阻塞。
在读操作远远高于写操作的环境中,可以保障线程安全的情况下,提高运行效率。
线程安全的集合
Collection集合体系下,除Vector 以外的线程安全集合。
Collections中的工具方法
Collections工具中提供了多个可以获得线程安全集合的方法。
JDK1.2提供,接口统一,维护性高,但性能没有提升,均已synchronized实现
CopyOnWriteArrayList
ArrsyList的一个线程安全辩题,其中所有可变操作(add、set等等) 都是通过对底层数据进行一次新的复制来实现。
线程安全的ArrayList,加强版读写分离。
写有锁,读无锁,读与写之间不阻塞,优于读写锁。
写入时,先copy一个容器副本、在添加新元素,最后替换引用。
使用方法与ArrayList无异。
接口引用,更容易实现更换引用类 List list = new CopyOnWriteArrayList(); => List list = new ArrayList() 更换子类无差异。
CopyOnWriteArraySet
ConcurrentHashMap
初始容器默认为16段(Segment),使用分段锁设计。
不对整个Map加锁,而是为每个Segment加锁。
当多个对象存入同一个Segment时,才需要互斥。
最理想状态为16个对象分别存入16个Setment,并行数量16.
使用方式与HashMap无异。
总结
线程池概念
获取线程池
CopyOnWriteArrayList
CopyOnWriteArraySet
Queue接口(队列)
Collection的子接口,表示队列FIFO(First In First Out)
ConcurrentLinkedQueue;
Queue的一个线程安全的队列。
线程安全、可高效率都城的队列,高并发下性能最好的队列。
无锁、CAS (compare and Swap)比较交换算法,修改的方法包含三个核心参数(V,E,N)
V:要更新的变量、E:预期值、N:新值。
只有当V==E,V=N;否则表示内容已经被更新过,则取消当前操作。
BlockingQueue接口(阻塞队列)
Queue的子接口,阻塞的队列,
阻塞队列
ArrayBlockingQueue:
数组结构实现,有界限列。(手工固定上线)
LinkedBlockingQueue:
链表结构实现,无界队列。(默认上线Integer.MAX_VALUE)
总结:
什么是流
概念:内存与存储设备之间传输数据的通道。
流的分类
按方向【重点】:
输入流:将<存储设备>中的内容读入到<内存>中。
输出流:将<内存>中的内容读入到<存储设备>中。
按单位:
字节流:以字节为单位,可以读写所有数据。
字符流:吃字符为单位,只能读写文本数据。
按功能:
节点流:具有实际传输数据的读写功能。
过滤流:在节点流基础上增强功能。(装饰器、装饰类)
字节流:
过字节流的父类(抽象类):
InputStream:字节输入流; 此抽象类是表示字节输入流的所有类的超类。
OutputStream:字节输出流; 此抽象类是表示输出字节流的所有类的超类。
FileOutputStrean:
public void write(byte[] b ) 一次写多个字节,将b数组中所有字节,写入输入流。
FileOutputStream output = new FileOutputStream("Files\test1.txt");
for (int i = 'a'; i < 'z'+1; i++) {
output.write(i);
}
byte[] bs = new byte[] {65,66,67,68,69,70};
output.write(bs,1,3);
FileInputStream:
public int read(byte[] b 从流中读取多个字节,将读到内容存入b数组中,返回实际读到的字节数;如果达到文件的尾部,则返回-1;
FileInputStream input = new FileInputStream("Files\test1.txt"); // 创建输入流
byte[] cache = new byte[1024*256]; //设置缓存数组大小
for (int i = 0; ;) { // 循环 或者 while true
int n = input.read(cache); // 读取数据并缓存入cache中
if(n == -1) {break;}; // 退出循环条件
for (int j = 0; j < n; j++) { //打印读取到的数据
System.out.print((char)cache[j] + " ");
}
System.out.println();
}
字节过滤流:
缓冲流:BufferedOutputStream / BufferedInputStream
提高IO效率,减少访问磁盘的次数。
数据缓存在缓冲区,flush是讲缓存区的内容写入文件中,也可以直接close。
OutputStream os = new FileOutputStream("Files\buffertest.txt"); //节点流
BufferedOutputStream bos = new BufferedOutputStream(os); //过滤流
bos.write('X'); //写入缓存之中
bos.flush(); //刷新缓冲(将缓冲中的数据,一次性写入文件中,并清空缓冲区)
bos.close(); // 级联执行flush()
BufferedInputStream 输入流的使用方法与建立数组缓存相同,且缓存大小默认为8192
InputStream fps = new FileInputStream("Files\buffertest.txt");
BufferedInputStream bis = new BufferedInputStream(fps);
while (true) {
int s = bis.read();
if(s == -1) {
break;
}
System.out.print((char)s+" ");
}
对象过滤流:
ObjectOutputStream / ObjectInputStream
使用流传输对象的过程称为序列化、反序列化。
因为String等常用类型 父类已实现接口 Serializable 所以可以直接使用序列化存储功能;
当文件读取到尾部时,使用EOFException作为终止循环判断条件:
InputStream ips = new FileInputStream("Files\object.txt");
ObjectInputStream oiStream = new ObjectInputStream(ips);
while (true) {
try {
Student student = (Student) oiStream.readObject();
System.out.println(student.toString());
} catch (EOFException e) {
break;
}
}
字符编码
当编码方式和解码方式不一致时,会出现乱码
字符流
字符流的父类(抽象类):
Reader:字符输入流,用于读取字符流的抽象类。
Writer:字符输出流,写入字符流的抽象类。
FileWriter:
public void write(String str) 一次写多个字符,将b数组中所有字符,写入输出流。
Writer writer = new FileWriter("Files\writeIndex2.html");
writer.write(cache);
writer.close();
FileReader:
public int read(char[] c) 从流中读取多个字符,将读到的内容存入c数组,返回实际读到的字符数;如果达到文件的尾部,则返回-1。
char[] cache = new char[1024*128];
Reader read = new FileReader("Files\index.html");
int n = 0;
while (true) {
n = read.read(cache);
if(n == -1) {break;};
}
字符过滤流
字符节点流
使用步骤:
创建节点流
[创建过滤流 设置字符编码集]
封装过滤流
读写数据
关闭流
总结:
File类
概念:代表物理盘符中的一个文件夹或文件。
listFiles( fileFilter ) 方法:
该方法无参数时将返回所在文件目录下的所有文件,加入参数时,参数将实现接口 FileFilter,并覆盖方法accept(File file)
for (File string : dirFile.listFiles(new myFilter())) { System.out.println(string); }
class myFilter implements FileFilter{
@Override
public boolean accept(File file) { //自定义判断条件,通过返回true,不通过false;
if(file.isFile()&& file.getName().endsWith(".html")) {
return true;
}
return false;
}}
什么是网络
由点和线构成,表示诸多对象间的相互联系。
什么是计算机网络
为实现资源共享和信息传递,哦谈过通信线路连接起来的若干主机(Host)
互联网:(Internet)点与点相连。
万维网:www world wide web 端与端的相连
物联网:IOT internet of things 物与物相连
网络编程:让计算机与计算机之间建立连接、进行通信。
网络模型:
OSI(oper system interconnection) 开放式系统互联
第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性,MAC
第三层:网络层负责定义了能够表示所有网络节点的逻辑地址。(IP地址)
第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排,(TCP、UDP)
第五层:会话层负责使用应用建立和维持会话,是通信在失效时继续恢复通信(断点续传)
第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII 格式传输。
第七层:应用层负责文件访问和管理,可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)
TCP/IP模型
一组用于实现网络互联的通信协议,将协议分成四个层次。
第一层:接口层负责建立电路连接,是整个网络的物理基础,点醒的洗衣包括以太网、ADSL等等。
第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
第三层:传输层负责传送文本数据,主要是协议是TCP、UDP协议。
第四层:应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
IP:
Port:
InetAddress类
基于TCP的网络编程
Socket编程:
Socket(套接字)是网络中的一个通信节点。
分为客户端Socket与服务器ServerSocket.
通信要求:IP地址 + 端口号。
开发步骤:
类对象
类的对象:基于某个类 new出来的对象,也称为实例对象。
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
获取类对象
通过类的对象,获取类对象
Student s = new Student();
Class c = s.getClass();
通过类名获取类对象
Class c = 类名.class;
通过静态方法获取类对象
Class c = Class.forName(“包名.类名”);
工厂设计模式
通开发中有一个非常重要的原则是“开闭原则”,对拓展开放、对修改关闭。
工厂模式主要负责对象创建的问题。
可通过反射进行工厂模式的设计,完成动态的对象创建。
使用反射创建类:
Class c = Teacher.class;
Teacher s2 = (Teacher)c.newInstance();
s2.name = "joba";
// 构造新对象
Teacher s4 = (Teacher)createObject("Teacher");
// 获得新对象的类型
Class<? extends Teacher> c4 = s4.getClass();
// 通过类型获得类方法
Method m = c4.getMethod("exam" , int.class);
// 执行有参方法,传入参数
Object result = m.invoke(s4 , 80);
// 打印返回的结果
System.out.println(result);
如果方法为私有方法 需使用
Method m = c4.getDeclaredMethod("calc", Double.class);
m.setAccessible(true);
m4.invoke(m, 100D);
单例模式
单例(Singleton): 只允许创建一个该类的对象。(天生线程安全)
创建单例对象所获得的对象为同一个:
1.饿汉式:天生线程安全、类加载创建(不好,不用的时候也被迫创建,占用一点点资源)
Singleton s = Singleton.getInstance();
System.out.println(s); //singleton_16.Singleton@15db9742
Singleton s1 = Singleton.getInstance();
System.out.println(s1); //singleton_16.Singleton@15db9742
class Singleton{
private static final Singleton instance = new Singleton();
private Singleton() {};
public static Singleton getInstance() {
return instance;
}
}
2.懒汉式:使用时在创建、天生线程不安全(加锁)
class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.懒汉式:用时在创建、天生线程安全
class Singleton{
private Singleton(){}
private static class Holder{
static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Holder.instance;
}
}
总结: