文章目录
JAVA SE基础
简介
java是一门面向对象的跨平台编程语言,且其是动态语言。
JDK1.8中文文档 https://www.matools.com/api/java8。
jdk、jre、jvm
jdk是java开发中所需要使用的依赖(java development kit)
jre是java程序运行时所要的依赖(java runtime environment)
jvm是java程序运行的地方(java virtual machine),也称java虚拟机其是实现跨平台的精髓所在
java代码编译->>运行
编译:首先通过javac命令编译成class文件
运行:最后通过java命令运行class文件
反编译命令:javap
注释
为了方便编码人员进行阅读代码,其重要作用就是解释所写代码意义,并且其不会被编译执行
单行注释
//这是单行注释
多行注释
/*
这是多行注释
*/
文档注释
文档注释说明类或方法的详细信息
/**
* @author changlei
* @version 1.0
*/
public class TestJava{
/**
*
* @param args
*/
public static void main(String[] args) {
}
}
注意:可以使用javadoc生成一个相应类的的帮助文档,步骤如下
标识符关键字
关键字
java关键字标明了其在java语言的特殊含义
class类、interface接口、@interface注解
标识符
标识符就是java中资源名称
//TestClass类名称
public Class TestClass{
//name变量名称
private String name;
//testMethod方法名称
private void testMethod(){return;}
}
标识符命名规则
标识符开头只能使用大小写英文字母,$符号,**_**下划线
标识符后可使用任意字符组合,但是特殊字符不能使用**`,~,!,@,#,%,^,&,*,(,),[,],{,},等等**一般除开$都不能使用
标识符命名不能使用java关键字
数据类型
计算机计量单位
二进制B,八进制O,十进制D,十六进制H
bit(二进制位)二进制位如1111B就是4bit
1B(字节)=8bit(二进制位)
1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
基本数据类型
byte字节型 1字节
short短型 2字节
int整型 4字节
long长整型 8字节
float单精度浮点型 4字节
double双精度浮点型 8字节
char字符型 2字节
boolean布尔型 取决于Java虚拟机,没有特定规定字节数
java标识不同进制数
2进制:int a=0b1001;(0B1001) 9
8进制:int a=01001; 1002
10进制:int a=1001; 1001
16进制:int a=1001; 4097
数据类型转换
高精度向低精度转换必须强制转换类型,而且可能会产生精度丢失;而低精度向高精度转换不需要强制转换类型
大字节向小字节转换会出现了内存溢出,从而导致数据异常
引用数据类型
//此为String类类型
String name;
//此为数组类型
int[] arry;
运算符
基本运算符
基本运算符包括算数运算符、逻辑运算符、位运算符三种
/*
a++:与a=a+1类似,注:操作时先进行运算再进行++
++a:与a=a+1类似,注:操作时先进行++再进行运算
a+=?:与a=a+?类似
a-=?:与a=a-?类似
a*=?:与a=a*?类似
a/=?:与a=a/?类似
*/
三元运算符
//条件判断? 条件真所赋值:条件假所赋值
int result=100>200? 1:0;
流程控制
顺序结构
从上到下依次执行代码
//顺序执行
int i=0;
System.out.println(i);
选择结构
跟据条件选择执行代码
//if-else条件选择
int a=1;
int b=2;
if (a==b){
System.out.println("相等");
}
else {
System.out.println("不相等");
}
//switch-case选择结构
int c=0;
switch (c){
case 0:
System.out.println("进入第一个分支");
break;
case 1:
System.out.println("进入第二个分支");
break;
case 2:
System.out.println("进入第三个分支");
break;
default:
System.out.println("其余条件都不满足,进入该分支");
break;
}
注:当switch语句所对应的case执行后不break时,其会变成顺序结构执行
循环结构
跟据条件多次执行代码
//for循环;j<10为真进入循环,否则退出循环;先判断后执行
for (int j = 0; j < 10; j++) {
System.out.println("代码循环了"+i+"次!");
}
//while循环;1==1为真进入循环,否则退出循环;先判断后循环
while (1==1){
System.out.println("进入了循环");
}
//do-while循环;1==1为真重新执行do方法块,否则不执行;先执行后判断
do {
System.out.println("进入了循环");
}while (1==1);
递归
简介
递归就是通过方法调用来实现自己调用自己
//递归方法
public static int sum(int i){
//递归头
if(i==1){
return 1;
}
//递归体
else {
return i+sum(i-1);
}
}
求和例子流程:
使用sum(3),判断递归sum(2),判断递归sum(1),判断递归结束返回1,返回2+1,返回3+2+1,程序结束。
递归分析
递归分为两个主要流程:①调用②返回
递归分为两个主要部分:①递归头(递归结束标志)②递归体(递归内容)
数组
简介
具有相同类型的集合,并且元素按照索引从0~???依次排列,一旦指定数组大小后就不允许改变了。
//第一种,建议使用 ([]位置随意)
int[] a;
//第二种
int a[][];
//二维数组
int[][] a;
int []a[];
初始化
//静态初始化
int[] a={1,2,3};
//动态初始化(指定了内容,int一般为0,String一般为null)
int[] a=new int[3];
a[0]=1;
a[1]=2;
a[2]=3;
注意点:
静态初始化后,不允许再次改变数组大小。
动态初始化后,可以允许重新初始化数组空间,但由于是重新开辟了堆空间,所以是生成的一个新数组。
数组自带方法
int[] a=new int[3];
//数组克隆:返回一个与原数组数据相同的新数组
int[] clone = a.clone();
//数组长度,返回数据的数据个数
int length = a.length;
注意:
当其是二维数组时,length方法返回的是二维数组的行数
原因由静态初始化可以看出{{},{},{},{}}
稀疏数组
简介
稀疏数组对于存在大量相同值的数组进行了容量优化,依据规则产生了一个新数组。
原数组:
{
{0,0,0,0,0},
{0,0,1,0,0}
}
稀疏数组:
{
{2,5,1},
{1,2,1}
}
稀疏数组规则:
第一行:原数组行数,原数组列数,特殊值个数
第二行:特殊值1行位置,特殊值1列位置,特殊值1值
第二行:特殊值2行位置,特殊值2列位置,特殊值2值
......
代码实现
//原数组
int[][] old={{0,0,0,0},{0,0,0,0},{1,0,2,0}};
showArray(old);
//稀疏数组初始化
int line= old.length;
int row= old[0].length;
int num=0;
for (int[] ints : old) {
for (int anInt : ints) {
if(anInt!=0)
{
num++;
}
}
}
int[][] newArray=new int[num+1][3];
//依照规则进行生成稀疏数组
newArray[0][0]=line;
newArray[0][1]=row;
newArray[0][2]=num;
for (int i = 0,newArrayLine=1; i < old.length; i++) {
for (int j = 0; j < old[i].length; j++) {
if(old[i][j]!=0){
newArray[newArrayLine][0]=i;
newArray[newArrayLine][1]=j;
newArray[newArrayLine][2]=old[i][j];
newArrayLine++;
}
}
}
showArray(newArray);
//将稀疏数组还原
int[][] after=new int[newArray[0][0]][newArray[0][1]];
for (int i = 1; i <newArray.length ; i++) {
after[newArray[i][0]][newArray[i][1]]=newArray[i][2];
}
showArray(after);
//打印二维数组
public static void showArray(int[][] array){
for (int[] arrayx : array) {
System.out.print("[");
for (int arrayy : arrayx) {
System.out.print(arrayy);
}
System.out.println("]");
}
}
注:这个在原数组特殊值过多时还是不推荐使用,因为在其稀疏数组转化时需要时间,且生成的新数组没有意义
OOP
简介
object oriented programming(面向对象程序设计)
OOP核心思想就是对于具有相同特性的事物,将其模板化。
类相当于模板,对象相当于跟据模板而生成的实例。
/*
类对象实例化原理说明:
new TestClass()在堆中申请了一块空间,将其空间地址指给了栈区中testJava变量的引用
*/
TestJava testJava=new TestClass();
//匿名对象的使用
new TestClass();
类分析
//权限修饰符 class 类名{类内容}
public class Persion {
//类成员变量
private String name;
/*
类无参构造器,其默认存在;
构造器默认第一行有super();语句
构造器与类名一致
构造器无返回值类型
*/
//无参构造器
public Persion() {
}
//类有参构造器;写了有参构造器后,类会失去默认构造器
public Persion(String name) {
this.name = name;
}
/*
java方法解释:
①注意java方法都必须在类中才能定义
②格式:权限修饰符 返回值类型 方法名(参数列表){}
*/
//类方法
public static void test1(){
}
//类成员方法
public void test2(){
}
}
类资源调用法分析:
静态资源:类名.资源名
类的开放资源:对象名.资源名
封装
简介
将类中资源私有化,只提供接口给外部进行使用。
private关键字的使用,privat修饰后代表此资源只能由本类中才能使用。
实例
public class TestClass {
//测试封装参数
private int testParament;
//普通参数
public int testParament1;
public TestClass() {
}
//获取封装参数的外部接口
public int getTestParament() {
return testParament;
}
//改变封装参数的外部接口
public void setTestParament(int testParament) {
this.testParament = testParament;
}
}
//测试类
public class Application {
public static void main(String[] args) {
TestClass testClass = new TestClass();
//封装资源使用外部接口进行使用
testClass.setTestParament(10);
System.out.println(testClass.getTestParament());
//普通资源使用,直接使用 类对象.资源
testClass.testParament1=10;
System.out.println(testClass.testParament1);
}
}
继承
简介
继承关键字extends,其代表一个子类(派生类)能获取父类(基类、超类)的所有非私有资源。
java只能进行单继承,但是可以多实现接口
java所有类都直接或间接继承Object类
权限修饰符继承再理解
public修饰的资源,继承后的资源任意位置可用
protected修饰的资源,继承后的资源只能在同包下才能使用
private修饰的资源,非本类都不能进行使用
this、super关键字理解
this 指代当前所在类的对象
super 指代当前类的直接父类对象
方法重写
重写分析:
-重写必须存在继承关系。
-非静态方法在子类重写后,子类对象在进行使用该方法时,其使用的就是重写后的方法了。
-重写方法重写的是方法的方法体,因此除了方法体其余必须与被重写方法一致。
-静态方法不能重写,其只属于当前类
多态
简介
一个对象的类型往往是确定的,但是其的引用指向却可以是派生类的对象
多态的前提必须有方法的重写
多态的实质就是相同的方法体,可以跟据操作对象的不同,而选择调用相应的方法体资源
例子
//Persion
public class Persion {
private String name;
protected int age;
public void testMethod(){
System.out.println("Persion");
}
}
//Student
public class Student extends Persion{
//方法重写校验注解
@Override
public void testMethod() {
System.out.println("Student");
}
}
instanceof理解
简介
该关键字说明两个对象之间是否具有对象树的纵向继承关系
对象名 instanceof 类名,如果对象的类不属于类的纵向继承树上,则会编译失败,抛出类型转换异常
/*
继承树
Object
Object->String
Object->Persion
Object->Persion->Student
Object->Persion->Teacher
*/
//student类
Student student = new Student();
//persion类
Persion persion = new Persion();
System.out.println((student instanceof Student));
System.out.println((student instanceof Persion));
System.out.println((student instanceof Teacher));
System.out.println((student instanceof Object));
System.out.println((student instanceof String));
向下造型与向上造型
存在直接或间接继承便可以使用向下造型、向上造型机制
//假设A->>B
A a=new B();//向上造型,子类对象指向父类引用
B b=(B)new A();//向下造型,父类对象指向子类引用,但是需进行强制类型转换
static理解
如果在类中资源标明了static关键字后,此类资源便是类所有对象所共有的。
标有static资源的资源是随着类加载时进行一起加载的。
抽象类
简介
抽象类就是将类进行了二次抽象,进行了更高的模板化。总的来说就是本类的方法不去实现,且规定让子类去实现。
抽象类定义使用abstract关键字,其本身不允许new;抽象方法定义使用abstract关键字,其方法体自己不能实现
抽象方法只能存在于抽象类中,且抽象类跟普通类无差异(抽象类不允许new)
子类在继承抽象类后必须去重写父类的所有抽象方法,否则会编译错误
例子
//抽象类
public abstract class TestObs {
private int i=0;
public void testMethod1(){
System.out.println("不是抽象方法");
}
//抽象方法
public abstract void testMethod2();
public abstract void testMethod3();
}
//实现类
public class TestObsImpl extends TestObs{
//必须重写所有的抽象方法
@Override
public void testMethod2() {
}
@Override
public void testMethod3() {
}
}
接口
简介
接口对于抽象类又进行了二次抽象化,变得更加的模板化了。其接口中只允许存在抽象方法(同样并不允许new)、静态常量
接口使用interface关键字,且接口里的抽象方法不用写abstract关键字
实现接口使用implements,且可以进行多实现。
java8后,接口中可以定义default,与static修饰的方法存在
例子
//接口
public interface TestInterface {
//使用abstract的方法
public abstract void testMethod1();
//不使用abstract但是效果一样;在interface中的方法都是抽象方法。
public void testMethod2();
//default方法只能在接口内部使用
default void testDefault(){
return;
}
//static方法
static void testStatic(){
return;
}
}
//实现类
public class TestInterfaceImpl implements TestInterface{
//必须重写所有抽象方法
@Override
public void testMethod1() {
}
@Override
public void testMethod2() {
}
}
内部类
简介
在类或方法里面重新定义的类统称内部类
内部类还是类或方法的资源,与传统的资源使用方式一样
内部类能使用外部类的所有资源,其本质还是类的资源
例子
//外部类
public class TestClass {
//外部类里的内部类
public class TestClassSon{
public void testMethod(){
System.out.println("外部类内部的方法");
}
}
//外部类的普通方法
public void testMethod(){
System.out.println("外部类的方法");
}
//外部类的方法里定义类
public void testMethod1(){
//方法里的内部类
class TestMethodClass{
public void testMethod(){
System.out.println("方法内部的类的方法");
}
}
//使用方法内部的内部类
new TestMethodClass().testMethod();
}
}
//测试类
public class Application {
public static void main(String[] args) {
TestClass testClass = new TestClass();
//生成外部类的内部类
TestClass.TestClassSon classSon = testClass.new TestClassSon();
}
}
匿名类
简介
事先没有定义的类,在需要使用时直接进行的定义的类就是匿名类。
匿名类是基于接口进行实现的,其必须依赖于接口(继承类也可以)
匿名类相当于接口的实现类,名字必须要与想要实现的的接口一致
对象没有确定的引用指向的用法,并不是匿名类(容易联想错)
//Persion
public class Persion {
private String name;
protected int age;
public void testMethod(){
System.out.println("Persion");
}
}
//测试类
public class Application {
public static void main(String[] args) {
//无确定引用指向的对象
new Persion().testMethod();
}
}
例子
//接口
public interface TestNoName {
public void testMethod();
}
//匿名类的使用
new TestNoName(){
@Override
public void testMethod(){
System.out.println("匿名类");
}
}.testMethod();
Lambda表达式
lambda表达式用作优化匿名类的代码
与匿名类一样需要依靠一个接口,但所依赖的接口必须是函数式接口
//测试函数式接口,函数式接口中只能有一个方法
public interface TestLambda {
void testMethod(String str);
}
//测试类
public class Application {
public static void main(String[] args) {
//匿名内部类
TestLambda lambda=new TestLambda() {
@Override
public void testMethod(String str) {
System.out.println("这是匿名类的使用!"+str);
}
};
lambda.testMethod("张三");
/*
lambda表达式优化
()->{};
()代表参数列表,可省略参数类型与(),但是无参数时必须保留()
{}代表函数体,函数体只有一行语句时可以省略{}
*/
//优化1
lambda=(String str)->{
System.out.println("这是lambda表达式优化1!"+str);
};
lambda.testMethod("张三");
//优化2
lambda=str -> {
System.out.println("这是lambda表达式优化2!"+str);
};
lambda.testMethod("张三");
//优化3
lambda=str -> System.out.println("这是lambda表达式优化3!"+str);
lambda.testMethod("张三");
}
}
Java异常机制
简介
程序在运行过程中所产生的意外情况,统称为异常
java异常处理分为检查性异常、运行时异常、错误
检查性异常,也可称为不可预见异常,比如打开一个不存在的文件或连接一个无效IP
运行时异常,也称为可预见异常,比如除0异常
错误,其不是异常,且不能被异常机制所控制,如JVM虚拟机崩溃
java异常框架
try、catch、finally、throw、throws
try尝试执行会抛出异常的代码。不影响后续代码执行
catch捕获try抛出的异常进行处理,可有多个捕获
finally必须执行的代码,无论是否抛出异常其都会执行(常用作收尾处理)
throw抛出相应的异常
throws将异常抛给方法使用者,用在方法后
//自定义异常类,继承于Exception类(或其派生类)
public class TestException extends RuntimeException{
@Override
public String toString() {
return "出现了我的自定义异常";
}
}
//测试自定义异常的抛出与捕获
try {//可能会出现的异常的代码区
testMethod(10);
} catch (TestException testException) {//进行捕获相应的异常,并进行处理
System.out.println(testException);
}
catch (Exception exception){//捕获未考虑到的异常抛出
System.out.println("出现了异常");
}
finally {//收尾工作
System.out.println("异常处理收尾工作");
}
//能产生自定义异常的方法
public static void testMethod(int n) throws TestException{//将异常抛给方法执行者
if(n>0){
throw new TestException();//抛出自定义的异常
}
}
JavaIO流
简介
I代表终端输入java的输入流,O代表java输出到终端的输出流
IO基于终端来说才有流的说法,与终端相连的通道可理解为流,通过流来对于终端设备进行输入输出。
IO终端可以是文件、键盘、网络等等
IO流打开后只能依次操作,因为流具有不选择、不可回溯的特性
InputStream、OutputStream是字节流的抽象类,所有的字节流都实现了它们,在java.io包下
Reader、Writer是字符流的抽象类,所有的字符流都实现了它们,在java.io包下
字节流到其它流有XXXStreamXXX桥梁类进行了转换,所以说字节流是所有流的基础
文件格式
计算机上所有的文件在计算机上储存的方式都是以字节的方式进行了存储。
所有的文件的根基都是字节,只是解释方法不同。
编码格式
字符集
ASCLL英文字符与标点符号
ISO8859欧洲字符集
GBK,GB2312,GB18030中文字符集
GJK中日韩字符集
Unicode全球统一编码字符集,全球所有的字符
编码格式
UTF-8 1~3个字节储存一个uicode字符
UTF-16 2个字节存储一个uicode字符
UTF-32 4个字节存储一个uicode字符
GBK 2个字节存储一个字符
ASCLL 1个字节存储一个字符
缓冲区
字节流与字符流的数据存储临时区。
都在java.nio包下
都是抽象类
ByteBuffer
字节的缓冲区
CharBuffer
字符的缓冲区
文件IO流
以文件为终端的IO流
/*
字节流
*/
public class Application {
public static void main(String[] args) throws IOException {
//创建文件
File file = new File("text.txt");
//打开文件输出流,可以设置写入时是否覆盖,默认不覆盖
OutputStream outputStream=new FileOutputStream(file);
//要输出的字节数组
byte[] bytes={1,2,3,4,5,6};
//向文件输出一个字节数组,每次输出覆盖原有内容
outputStream.write(bytes);
//关闭输出流,否则浪费资源
outputStream.close();
//打开文件输入流
InputStream inputStream=new FileInputStream(file);
//字节数组缓冲区
byte[] bytesBufer=new byte[2048];
//读取文件数据读取长度为缓冲区大小,存放在缓冲区中,返回读入缓冲区的字节数,无数据后返回-1
inputStream.read(bytesBufer);
for (int i = 0; i < bytes.length; i++) {
System.out.print(bytesBufer[i]+",");
}
//关闭输入流,否则浪费资源
inputStream.close();
}
}
/*
字符流
*/
public class Application {
public static void main(String[] args) throws IOException {
//获取一个文件对象
File file = new File("text.txt");
//打开文件输出流,可以设置写入时是否覆盖,默认不覆盖
Writer writer=new FileWriter(file);
//向文件输出一个字符串,每次输出覆盖原有内容
writer.write("hello word!");
//关闭输出流,否则浪费资源
writer.close();
//定义字符缓冲区,用于接受字符数据
CharBuffer charBuffer=CharBuffer.allocate(2048);
//打开文件输入流
Reader reader=new FileReader(file);
//读取文件数据,存放在缓冲区,返回读入缓冲区的字符数,无数据后返回-1
reader.read(charBuffer);
//将字符缓冲区数据转为字符数组进行遍历
for (char c : charBuffer.array()) {
System.out.print(c);
}
//关闭输入流,否则浪费资源
reader.close();
}
}
大文件IO操作
策略段式操作:一段段输出,一段段输入。
/*
字节流
*/
public class UtilByte {
//终端
private File remoteFile;
//字节缓冲区
private byte[] byteBuffer =new byte[512];
//设置终端
public UtilByte(File remoteFile) {
this.remoteFile = remoteFile;
}
//字节流获取数据
public void input() throws IOException {
//打开文件输入流
InputStream inputStream=new FileInputStream(remoteFile);
//循环读数据
while (true){
if (inputStream.read(byteBuffer) == -1) {判断数据是否读完
break;
}
//向指定文件输出所读数据
output(byteBuffer);
//遍历所读数据,由于所读数据为字节数组,首先因生成字符串再进行读取
String info=new String(byteBuffer,"utf-8");
System.out.println(info);
//清空缓冲区数据,保证数据正常
for (int i = 0; i < byteBuffer.length; i++) {
byteBuffer[i]=0;
}
}
}
//字节流输出数据
public void output(byte[] bytes) throws IOException {
OutputStream outputStream=new FileOutputStream("test.txt",true);
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
}
}
/*
字符流
*/
public class UtilChar {
//终端
private File remoteFile;
//字符缓冲区
CharBuffer charBuffer=CharBuffer.allocate(100);
//设置终端
public UtilChar(File file) {
this.remoteFile = file;
}
//字符流取数据
public void input() throws IOException {
//打开文件输入流
Reader reader=new FileReader(this.remoteFile);
//循环读数据
while (true){
if (reader.read(charBuffer)==-1){//判断数据是否读完
break;
}
for (char c : charBuffer.array()) {//遍历所读数据
System.out.print(c);
}
output(charBuffer.array());//将所读数据输出到指定文件中
char[] chars=new char[100];//清空数组
//清空缓冲区,保证数据正常
charBuffer.position(0);//1、设置位置为初始位置
charBuffer.put(chars);//2、清空原有数据
charBuffer.position(0);//3、设置位置为初始位置
}
//关闭文件输入流
reader.close();
}
//字符流输出数据
public void output(char[] c) throws IOException {
//打开文件输出流,并设置为追加模式
Writer writer=new FileWriter(new File("test.txt"),true);
//输出数据
writer.write(c);
writer.flush();
//关闭输出流
writer.close();
}
}
对象序列化
简介
java对象序列化就是将java对象转为字节序列。
java反序列化就是将字节序列转化为java对象。
使用ObjectXXXXStream流进行序列化与反序列化。
序列化实现
类需要实现序列化必须实现Serializable接口,标记此类可以序列化
Java多线程
简介
程序用编程思维来说是数据结构与算法的结合,其是静态的。
进程是程序的一次动态运行,其是一次动态过程。
线程是进程的执行单位,一个进程对应多个线程。且线程享有进程的所有资源。
Java线程分为用户线程(Main线程)、守护线程(GC垃圾回收线程)两大线程
线程原理:将原来进程中的同步执行执行变成了异步执行,让进程执行更加高效。
进程运行原理:必须一步一步进行运行。
引入线程后的运行原理:步骤允许并行执行。
线程相当于另一个程序,但是共享资源
Java实现多线程
继承Thread类
实现步骤
自定义线程类继承Thread
重写run方法,编写自定义线程执行体
创建自定义线程类对象
执行start方法,则开辟了一个自定义线程
//继承Thread类,Thread其实是Runnable的一个实现类
public class TestThread extends Thread{
public TestThread() {
}
public TestThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+"执行"+i);
}
}
}
//测试类
public class Application {
public static void main(String[] args) {
//开辟新线程
TestThread testThread = new TestThread("Thread子线程");
testThread.start();
//主线程操作
Thread thread = Thread.currentThread();
thread.setName("主线程");
//主线程
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+"执行"+i);
}
}
}
实现Runnable接口
实现步骤
自定义线程类实现Runnable接口
重写run方法,编写自定义线程执行体
使用自定义线程对象创建一个Thread对象
使用Thread对象执行start方法,则开辟了一个自定义线程
//实现Runnable接口,Runnable接口中只有run一个抽象方法
public class TestRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+"执行"+i);
}
}
}
//测试类
public class Application {
public static void main(String[] args) {
//开辟新线程
new Thread(new TestRunnable(),"Runnable子线程").start();
//主线程操作
Thread thread = Thread.currentThread();
thread.setName("主线程");
//主线程
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+"执行"+i);
}
}
}
实现Callable接口
实现步骤
线程实例-龟兔赛跑
/*
龟兔赛跑模拟线程类
兔子线程我们进行特殊处理,乌龟线程我们直接放行。
获胜条件,谁先跑满100步
兔子跑步到50步进行休息
*/
public class GameThread implements Runnable{
private static String winner;
@Override
public void run() {
gameRun();
}
//比赛运行控制
public void gameRun(){
for (int i = 1; i < 200; i++) {
if (gameOver(i)) {
System.exit(0);
}
if (Thread.currentThread().getName().equals("兔子")&&i==50){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步!");
}
}
//比赛结束判断
public boolean gameOver(int num){
if (num == 100&&winner==null) {
winner=Thread.currentThread().getName();
System.out.println(winner+"赢得比赛!");
return true;
}else {
return false;
}
}
}
//测试类
public class Application {
public static void main(String[] args) {
//乌龟跑步线程
new Thread(new GameThread(),"乌龟").start();
//兔子跑步线程
new Thread(new GameThread(),"兔子").start();
}
}
线程状态
简介
线程拥有5个状态,包含了线程从创建到死亡的形式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lzm9fBjJ-1607156272854)(JavaSE.assets/image-20200918162012356.png)]
常见方法
//测试类
public class Application {
public static void main(String[] args) throws InterruptedException {
//测试线程
Thread thread=new Thread(()-> System.out.println("线程为:"+Thread.currentThread().getName()),"张三");
//获取线程状态NEW(新建)、RUNNABLE(运行中)、BLOCKED(阻塞)、TERMINATED(终止)
System.out.println(thread.getState().toString());
//获取线程优先级,默认为5,最高为10,最低为1
System.out.println(String.valueOf(thread.getPriority()));
//当前线程休眠ms,线程状态转为阻塞,但不会释放线程锁
Thread.sleep(10);
//当前线程转交CPU控制权,状态转为就绪状态,但可能让步失败
Thread.yield();
//指定线程抢占CPU资源,指定线程执行完成后,CPU才进行调度资源
thread.join();
Thread.State
}
}
守护线程
Java线程分为用户线程与守护线程
守护线程守护用户线程的执行
JVM只有当用户线程执行完毕就进行关闭,守护线程跟随JVM的关闭而关闭
//守护线程
public class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝守护你!");
}
}
}
//用户线程
public class People implements Runnable{
@Override
public void run() {
for (int i = 1; i < 36000; i++) {
System.out.println("你活了"+i+"天!");
}
System.out.println("你死了!");
}
}
//测试类
public class Application {
public static void main(String[] args) throws InterruptedException {
//守护线程启动
Thread god = new Thread(new God());
god.setDaemon(true);
god.start();
//用户线程启动,新建Thread默认为用户线程
Thread people = new Thread(new People());
people.setDaemon(false);
people.start();
}
}
线程同步
简介
多个线程在操作共有资源区时,由于线程的不可控性可能会导致数据异常,此称为线程不安全。
线程同步原理:一个线程在操作共有资源时(对共有资源进行上锁),其它线程不允许操作共有资源(其余线程进行排队等待),只有等当前线程操作完毕后(共有资源释放锁),其余线程才能对于共有资源进行操作
synchronized同步锁
/*
银行卡类:花钱线程共有资源类
*/
public class Car{
public int money;
public Car(int money) {
this.money = money;
}
}
/*
用户花钱线程类,其拥有银行卡资源类
*/
public class DoCar implements Runnable{
Car myCar;//银行卡类
public DoCar(Car myCar) {//将用户银行卡与花钱进行绑定
this.myCar = myCar;
}
@Override
public void run() {
//获取到银行卡共有资源的锁,保证线程安全
synchronized (myCar){
doMoney(70);
}
}
/*
线程不安全原因:
线程在操作共有资源操作过程中,其它线程也在对共有资源进行操作,所以说有大概率会出现数据异常
*/
public void doMoney(int domoney){
if (myCar.money-domoney>=0) {
System.out.println(Thread.currentThread().getName()+"->>花了"+domoney+"元");
myCar.money-=domoney;
System.out.println("余额:"+myCar.money);
}
else{
System.out.println(Thread.currentThread().getName()+"->>的余额不足");
}
}
}
//测试类
public class Application {
public static void main(String[] args) throws InterruptedException {
//模拟两个用户使用同一张银行卡进行消费
Car car = new Car(100);
new Thread(new DoCar(car),"张三").start();
new Thread(new DoCar(car),"李四").start();
}
}
Lock锁
lock锁是synchronized的一种显示实现。JDK5后引入。
使用ReentrantLock工具类,其中lock方法是当前线程获取其对象锁,unlock当前线程释放其对象锁。
/*
银行卡类:花钱线程共有资源类
这里继承了ReentrantLock类,可以实现资源加锁机制
*/
public class Car extends ReentrantLock {
public int money;
public Car(int money) {
this.money = money;
}
}
/*
用户花钱线程类,拥有银行卡资源类
*/
public class DoCar implements Runnable{
Car myCar;//银行卡类
public DoCar(Car myCar) {//将用户银行卡与花钱进行绑定
this.myCar = myCar;
}
@Override
public void run() {
//共有资源进行加锁,保证线程安全,获取资源锁可能失败所以应该放入try块中。
try {
//银行卡加锁
myCar.lock();
doMoney(70);
} catch (Exception exception) {
exception.printStackTrace();
}finally {
/*
银行卡释放锁
此步骤应该放入finally块中,因为不管锁是否获取到,当前线程都应该释放锁
*/
myCar.unlock();
}
}
/*
线程不安全原因:
线程在操作共有资源操作过程中,其它线程也在对共有资源进行操作,所以说有大概率会出现数据异常
*/
public void doMoney(int domoney){
if (myCar.money-domoney>=0) {
System.out.println(Thread.currentThread().getName()+"->>花了"+domoney+"元");
myCar.money-=domoney;
System.out.println("余额:"+myCar.money);
}
else{
System.out.println(Thread.currentThread().getName()+"->>的余额不足");
}
}
}
//测试类
public class Application {
public static void main(String[] args) throws InterruptedException {
//模拟两个用户使用同一张银行卡进行消费
Car car = new Car(100);
new Thread(new DoCar(car),"张三").start();
new Thread(new DoCar(car),"李四").start();
}
}
线程协作
简介
wait线程变为等待状态,释放锁
notify唤醒一个等待线程
notifyAll唤醒所有等待线程
生产者消费者问题
在线程互相协作中,会出现生产者线程生产数据,消费者线程消费生产者生产的数据。
生产者与消费者有先后关系,这时就体现出线程的协作了。
以下使用了管程法实现(管程法:使用特定的对象来管理线程共享资源):
/*
节目
节目资源类,作为缓冲区的资源
*/
public class Tv {
public String tvName;
public Tv(String tvName) {
this.tvName = tvName;
}
}
/*
生产者线程
生产者生产缓冲区的资源
*/
public class Product implements Runnable {
public TvBuffer tvBuffer;
public String[] pName = {"新闻联播", "天气预报", "今日说法", "大风车", "奥特曼"};
public Product(TvBuffer tvBuffer) {
this.tvBuffer = tvBuffer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
tvBuffer.addTv(new Tv(pName[i % pName.length]));
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("生产出错");
e.printStackTrace();
}
if (i==99){
System.out.println(Thread.currentThread().getName()+"生产者下班了");
System.exit(0);
}
}
}
}
/*
消费者线程
消费者消费缓冲区的资源
*/
public class Consumer implements Runnable {
TvBuffer tvBuffer;
public Consumer(TvBuffer tvBuffer) {
this.tvBuffer = tvBuffer;
}
@Override
public void run() {
for (int i = 0; i < 400; i++) {
try {
tvBuffer.deleteTv();
} catch (InterruptedException e) {
System.out.println("消费出错");
e.printStackTrace();
}
}
}
}
/*
节目缓冲区,缓冲大小未10
生产者生产节目
消费者消费节目
*/
public class TvBuffer {
//tv资源
public Tv[] tvs=new Tv[10];
//当前缓冲区所有的tv资源数
public int tvCount=0;
//生产者生产节目
public synchronized void addTv(Tv tv) throws InterruptedException {
//如果缓冲区满,等待生产
if (tvCount==tvs.length){
System.out.println("节目缓冲区满了,等待消费");
wait();
}
//生产节目,并通知消费
for (int i = 0; i < tvs.length; i++) {
if (tvs[i]==null){
System.out.println(Thread.currentThread().getName()+"生产:"+tv.tvName);
tvs[i]=tv;
tvCount++;
break;
}
}
notifyAll();
}
//消费者消费节目
public synchronized void deleteTv() throws InterruptedException {
//如果缓冲区为空,等待消费
if (tvCount==0){
System.out.println("缓冲区为空,等待生产");
wait();
}
//消费节目,并通知生产
for (int i = 0; i < tvs.length; i++) {
if (tvs[i]!=null){
System.out.println(Thread.currentThread().getName()+"消费:"+tvs[i].tvName);
tvs[i]=null;
tvCount--;
break;
}
}
notifyAll();
}
}
//测试类
public class Application {
public static void main(String[] args) throws IOException {
TvBuffer tvBuffer = new TvBuffer();
new Thread(new Product(tvBuffer),"生产者1").start();
new Thread(new Product(tvBuffer),"生产者2").start();
new Thread(new Consumer(tvBuffer),"消费者1").start();
}
}
线程池
简介
java线程在创建与销毁是需要时间的。因此我们可以使用一种将所有线程放在一个池子中进行统一管理,来提高性能,也就是线程池技术。
例子
线程池服务实现步骤:
1、使用Executors类创建一个线程池服务对象,使用ExecutorService来进行接受对象
2、使用ExecutorService对象执行相应线程,用法:线程池服务对象.execute(Runnable thread);
3、关闭线程池服务
//测试线程
public class TestThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"正在执行!");
}
}
//测试类
public class Application {
public static void main(String[] args){
//开启线程池服务
ExecutorService threadPool = Executors.newFixedThreadPool(2);
//执行线程
threadPool.execute(new TestThread());
threadPool.execute(new TestThread());
threadPool.execute(new TestThread());
threadPool.execute(new TestThread());
//关闭线程池服务
threadPool.shutdown();
}
}
Socket通信
简介
Socket编程就是Java中基于网络传输层TCP/UDP的编程。
IP
简介
IP是在网络通信中定位主机的位置的参数。
IP分为IPV4(32位)、IPV6(128位),两者区别就是地址所占bit数不同。
InetAddress
简介
inetaddress类是java中提供表示ip的类。
常用方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//获取指定域名或IP的IP封装对象
InetAddress ip = InetAddress.getByName("localhost");
//获取规范的主机名
System.out.println(ip.getCanonicalHostName());
//获取主机地址
System.out.println(ip.getHostAddress());
//获取主机名字
System.out.println(ip.getHostName());
//获取主机IP地址以字节数组进行返回
for (byte address : ip.getAddress()) {
System.out.println(address);
}
}
}
端口
简介
端口就是计算机上的资源定位参数。
当外部计算机访问计算机资源时,首先通过IP进行主机定位,然后在进行资源定位,这才是网络资源的定位方式。
TCP与UDP资源端口是分开存在的,每个各有65535个端口。
DOS查看端口情况命令:netstat -an
InetSocketAddress
简介
inetsocketaddress类是java中表示socket通信URL定位的类。
inetsocketaddress由IP和端口组成,其就是IP与端口组合类。
常用方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//使用特定的IP与端口构造InetSocketAddress对象
InetSocketAddress socketAddress = new InetSocketAddress(InetAddress.getByName("localhost"),9999);
//获取IP地址
socketAddress.getAddress();
//获取主机名
socketAddress.getHostName();
//获取端口号
socketAddress.getPort();
}
}
TCP
简介
TCP面向连接的传输层的通信协议。
TCP传输资源都需要建立连接,传输资源结束则断开连接。
TCP连接原理(可靠性)
连接两方为甲、乙以便于过程描述
TCP三次握手建立连接:
1、甲:我要建立连接
2、乙:你可以建立连接了
3、甲:我要开始发送数据了
TCP四次挥手释放连接:
1、甲:我要断开连接了
2、乙:你可以断开连接了
3、乙:我已经断开连接了
4、甲:我断开连接了
TCP客户端实例
public class TCPClient {
public static void main(String[] args) throws Exception{
//创建与指定IP端口的资源的socket通信
Socket client = new Socket(InetAddress.getByName("localhost"),9999);
//利用服务器连接对象获取输出流,用作向网络终端写入数据
OutputStream outputStream = client.getOutputStream();
//准备数据处理缓冲区
byte[] buffer=new byte[1024];
//设置发送信息
buffer="hello tcp".getBytes();
//利用网络输出流向指定远程资源发送数据
outputStream.write(buffer,0,buffer.length);
//关闭资源流
outputStream.close();
client.close();
}
}
TCP服务端实例
public class TCPServer {
public static void main(String[] args) throws Exception{
//创建服务器资源
ServerSocket serverSocket = new ServerSocket(9999);
//服务器资源等待客户连接,产生客户端连接对象
Socket server = serverSocket.accept();
//通过客户端连接对象获取输入流,以网络为终端获取数据
InputStream inputStream = server.getInputStream();
//准备数据处理缓冲区
byte[] buffer=new byte[1024];
//利用网络输入流处理数据
while (inputStream.read(buffer)!=-1){
System.out.println(new String(buffer));
}
//关闭资源流
inputStream.close();
server.close();
}
}
UDP
简介
UDP面向无连接的传输层的通信协议。
UDP通信不需要进行连接,我们只需要发送数据包,而对面也只需要接收数据包,因此不保证可靠。
UDP实现
UDP用户1(进行发送信息)
public class UDP1 {
public static void main(String[] args) throws Exception{
//建立UDP数据包,一般需指定当前资源端口
DatagramSocket udp1 = new DatagramSocket(1234);
//准备数据处理缓冲区
byte[] buffer=new byte[1024];
//设置发送信息
buffer="hello udp".getBytes();
//建立数据包,像数据包装配信息(发送的信息,发送的资源定位信息(IP与端口))
DatagramPacket udp1Packet = new DatagramPacket(buffer,0,buffer.length,new InetSocketAddress(InetAddress.getByName("localhost"),9999));
//通过UDP通信对象进行发送数据包
udp1.send(udp1Packet);
//关闭资源流
udp1.close();
}
}
UDP用户2(进行接收信息)
public class UDP2 {
public static void main(String[] args) throws Exception{
//建立UDP数据包,一般需指定当前资源端口
DatagramSocket udp2 = new DatagramSocket(9999);
//准备数据处理缓冲区
byte[] buffer=new byte[1024];
//建立接收数据包
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
//接收数据包
udp2.receive(packet);
//处理接收的信息
System.out.println(new String(buffer));
//关闭资源流
udp2.close();
}
}
URL类
简介
URL类是Java表示网络资源定位的类。
常用方法
一般方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//通过一个URL构建一个URL对象
URL url = new URL("https://baike.baidu.com/item/TCP/33012?fr=aladdin");
//获取作者名
url.getAuthority();
//获取URL的文件内容
url.getContent();
//获取默认端口
url.getDefaultPort();
//获取URL的文件名,其指的是URL的端口号后端内容
url.getFile();
//火球主机名
url.getHost();
//获取URL资源的路径部分
url.getPath();
//获取URL的端口号
url.getPort();
//获取URL的协议名
url.getProtocol();
//获取URL的参数
url.getQuery();
}
}
下载网络资源
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//通过一个URL构建一个URL对象
URL url = new URL("https://baike.baidu.com/item/TCP/33012?fr=aladdin");
//使用URL构建连接
URLConnection urlConnection = url.openConnection();
/*
通过连接获取资源输入流,也可以通过URL直接打开资源输入流
InputStream inputStream = url.openStream();
*/
InputStream inputStream = urlConnection.getInputStream();
//文件保存流
FileOutputStream fileOutputStream = new FileOutputStream("test.txt");
//数据处理缓冲区
byte[] buffer=new byte[1024];
//读取数据并存入数据
while (inputStream.read(buffer)!=-1){
fileOutputStream.write(buffer);
System.out.println(new String(buffer));
}
//关闭资源流
fileOutputStream.close();
inputStream.close();
}
}
注解与反射
注解
简介
注解和注释都是对于程序进行解释说明。
注解对于程序执行有辅助功能
注解配合反射可以对其注解的类赋值
元注解
元注解是在定义注解时所需要的辅助注解
//表明注解的注解位置,方法、类等等
@Target(ElementType.METHOD)
//表明注解的生效时间段,源文件、class文件、运行时
@Retention(RetentionPolicy.SOURCE)
//表明该注解被文档化
@Documented
//表明注解可以被实现了该类的子类继承
@Inherited
内置注解
java提供3个内置注解
//方法重写校验注解
@Override
//不鼓励使用标志注解
@Deprecated
//镇压警告注解
@SuppressWarnings("all")
自定义注解
使用@interface可以自定义注解
//自定义注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnontation {
String value() default "first annotation";
}
//测试类
public class Application {
public static void main(String[] args){
Application.testMethod();
}
//测试自定义注解
@MyAnontation
public static void testMethod(){
return;
}
}
反射机制
简介
java类在运行时JVM都会产生唯一一个Class类的实例对象,reflect(反射)
Class类存放了类的所有信息包括类的继承关系、实现关系、类本身信息、注解信息等等信息
在程序运行中,可以通过Class类操作类的所有资源,这就是反射的原理
由此可知反射可以操作已经定义好的信息,这就是语言的动态,但是同时其也带来了程序安全问题
获取Class对象
JVM针对于一个类来说只会生成唯一一个Class的实例对象
Class类就是反射机制的操作类
//反射测试类
public class TestObject{
private String name;
private int age;
public void testMethod(){
return;
}
}
//测试类
public class Application {
public static void main(String[] args) throws ClassNotFoundException {
//测试类对象
TestObject testObject = new TestObject();
//方法1 使用实例对象getClass方法
Class c1 = testObject.getClass();
//方法2 使用类资源class方法
Class c2 = TestObject.class;
//方法3 使用Class的静态方法forName加载相应类的资源(包全路径)
Class c3=Class.forName("code.reflect.TestObject");
//方法4 java内置类使用类资源TYPE
Class c4 = Integer.TYPE;
}
}
类加载原理
1、类加载,利用双亲委派机制进行选择相应的类加载器,使用类加载器进行加载
2、类链接,将类的类资源链接到JVM运行时环境中
3、类初始化,创建类的实例化对象,就会对于类进行初始化
获取类资源
//反射测试类
public class TestObject{
public String name;
private int age;
public TestObject(){}
public void testMethod(){
return;
}
}
//测试类
public class Application {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
//获取TestClass的Class反射对象
Class<TestObject> c1 = TestObject.class;
//获取名为name的字段,必须是public修饰
Field name = c1.getField("name");
//获取所有的字段,必须是public修饰
Field[] fields = c1.getFields();
//获取名为name的字段,无视权限修饰符
Field declaredname = c1.getDeclaredField("name");
//获取所有的字段,无视权限修饰符
Field[] declaredFields = c1.getDeclaredFields();
//获取名为testMethod,参数列表为null的方法,必须是public修饰
Method testMethod = c1.getMethod("testMethod", null);
//获取所有的方法,必须是public修饰
c1.getMethods();
//获取名为testMethod,参数列表为null的方法,无视权限修饰符
c1.getDeclaredMethod("testMethod",null);
//获取所有的方法,无视权限修饰符
c1.getDeclaredMethods();
//获取参数列表为null的构造器,必须是public修饰
c1.getConstructor(null);
//获取所有的构造器,必须是public修饰
c1.getConstructors();
//获取参数列表为null的构造器,无视权限修饰符
c1.getDeclaredConstructor(null);
//获取所有的构造器,无视权限修饰符
c1.getDeclaredConstructors();
}
}
反射对象生成实例化对象
//反射测试类
public class TestObject{
public String name;
private int age;
public TestObject(){}
public void testMethod(){
System.out.println("hello word");
return;
}
}
//测试类
public class Application {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//获取反射对象
Class<TestObject> c1 = TestObject.class;
//方法1 通过反射对象创建,这种方法需要无参构造
TestObject testObject = c1.newInstance();
//方法2 通过获取特定的构造器进行生成对象,传入对应的参数列表
TestObject testObject1 = c1.getConstructor(null).newInstance(null);
}
}
反射执行方法
//反射测试类
public class TestObject{
public String name;
private int age;
public TestObject(){}
public void testMethod(){
System.out.println("hello word");
return;
}
}
//测试类
public class Application {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//获取反射对象
Class<TestObject> c1 = TestObject.class;
//获取特定的方法
Method testMethod = c1.getDeclaredMethod("testMethod", null);
//利用反射对象生成实例化对象
TestObject testObject = c1.newInstance();
//执行方法,需要执行方法的对象,以及所需传入的参数
testMethod.invoke(testObject,null);
}
}
反射操作注解
该例子使用反射获取注解信息,然后使用相应的注解的变量对于类进行赋值
//自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAonotation {
String name() default "张三";
int age() default 10;
}
//测试反射操作注解
@TestAonotation(name = "李四",age = 20)
public class TestClass{
private String name;
private int age;
public TestClass() {
//获取反射Class对象
Class<? extends TestClass> aClass = this.getClass();
//通过反射对象获取字段
Field[] fields = aClass.getDeclaredFields();
//通过反射对象获取注解信息
TestAonotation testAonotation = (TestAonotation) aClass.getAnnotation(TestAonotation.class);
//获取注解信息对于类变量进行数据绑定
this.name= testAonotation.name();
this.age= testAonotation.age();
}
@Override
public String toString() {
return "TestClass{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//测试类
public class Application {
public static void main(String[] args){
TestClass testClass = new TestClass();
System.out.println(testClass.toString());
}
}
集合框架
简介
集合是一组对象的联合
数组所存类型可以是基本类型和引用类型,但是集合只能存引用类型
集合框架图
Collection
集合的顶级父接口
/*
测试类
*/
public class Application {
public static void main(String[] args) throws IOException {
//定义一个集合对象
Collection collection=new ArrayList();
//集合添加元素
collection.add(new String("张三"));
//向集合中添加指定集合中的内容
collection.addAll(collection);
//清理集合中的所有元素
collection.clear();
//判断集合中是否有指定数据
collection.contains(new String("张三"));
//判断集合中是否有指定集合中的所有内容
collection.containsAll(collection);
//判断集合是否为空
collection.isEmpty();
//返回一个集合迭代器
Iterator iterator = collection.iterator();
//移除集合中的指定元素
collection.remove(new String("张三"));
//移除集合中指定集合中的所有内容
collection.removeAll(collection);
//集合中仅仅只保留所指定集合的的内容
collection.retainAll(collection);
//将集合元素生成一个数组
Object[] objects = collection.toArray();
//返回集合元素个数
collection.size();
}
}
Interator
迭代器,每个集合都有一个迭代器,用于遍历
迭代器在操作时不允许其它使用remove函数
/*
测试类
*/
public class Application {
public static void main(String[] args) throws IOException {
//定义一个集合对象
Collection collection=new ArrayList();
//集合添加元素
collection.add(new String("张三"));
//向集合中添加指定集合中的内容
collection.addAll(collection);
//返回集合的迭代器
Iterator iterator = collection.iterator();
//判断迭代数据是否为空
iterator.hasNext();
//返回迭代数据,指针后移
iterator.next();
//将当指向数据从集合中删除
iterator.remove();
}
}
泛型
简介
泛型JDK1.5后引入的新技术
泛型主要作用将数据类型作为参数进行传递使用,以增强代码重用性
泛型可作用与类、接口、方法上
泛型
简介
泛型JDK1.5后引入的新技术。
泛型的意义:让资源脱离具体化从而提升资源的一般化,以此来加强此资源的复用性。
泛型可作用与类、接口、方法上。
使用泛型的两大步骤:一:创建泛型资源;二:使用泛型资源
< T >泛型声明,T为泛型的类型。
泛型类
在类中使用了泛型资源的类叫做泛型类。
泛型类加强了类对于处理多种资源的一般性。
/*
泛型类
类名后添加<T>表示类为泛型类
T表示占位符,可以随意命名
*/
public class MyGeneralClass <T>{//泛型类定义语法:在类名后面进行定义泛型声明
//使用泛型的变量
T testFiled;
//使用泛型的方法
public T testMethod(T testFiled){
return testFiled;
}
}
/*
测试类
*/
public class Application {
public static void main(String[] args){
//使用泛型类语法:构造泛型类对象时在构造函数参数列表前传入资源类型
//传入String类型
System.out.println(new MyGeneralClass<String>().testMethod(new String("张三")));
//传入Integer类型
System.out.println(new MyGeneralClass<Integer>().testMethod(new Integer(100)));
}
}
泛型接口
在接口中使用了泛型资源的接口叫做泛型接口。
泛型接口加强了接口对于处理多种资源的一般性。
/*
泛型接口
接口名后加<T>,表示此接口为泛型接口
T为占位符
*/
public interface MyGeneralInterface <T>{//泛型接口定义语法与泛型类一致。
//使用泛型的方法
T testMethod(T testFiled);
}
/*
实现泛型接口
实现方式
1、实现的泛型接口后面确定接口参数类型
2、通过泛型类再次泛型化
*/
public class MyGeneralInterfaceImpl<T> implements MyGeneralInterface<T>{
//实现的泛型方法
@Override
public T testMethod(T testFiled) {
return testFiled;
}
}
/*
测试类
*/
public class Application {
public static void main(String[] args){
//传入String类型
System.out.println(new MyGeneralInterfaceImpl<String>().testMethod(new String("张三")));
//传入Integer类型
System.out.println(new MyGeneralInterfaceImpl<Integer>().testMethod(new Integer(100)));
}
}
泛型方法(重点)
在方法中使用了泛型资源的的方法叫做泛型方法。
泛型方法加强了方法对于处理多种资源的一般性。
泛型方法在不依靠泛型类的资源类型时,其真正处理时资源时,资源的类型是从方法参数上获取的。
在使用泛型方法时,由于方法中资源类型是采用了传递来的方法参数的资源类型,所以说在方法中定义了多个泛型参数的情况下,那么在使用此方法时传递的泛型参数只能为一个资源类型,否则方法内无法识别到底是使用用那个泛型参数所提供的资源类型,来确定方法中所使用的资源类型。
泛型资源:
public <T> T testMethod(T t1,T t2) {//定义语法:在方法返回值类型前进行定义
T testT = t1;
testT = t2;
return testT;
}
使用泛型方法:
int test = new MyGeneralMethod().testMethod(1, 9);//正确用法
String test = new MyGeneralMethod().testMethod(new String("p1"),new String("p2"));//正确用法
int test = new MyGeneralMethod().testMethod(1,new String("p2"));//错误用法
List
简介
List接口作为collection的分支,称为有序集合
List元素特性为有序性、可重复性
ListIterator
列表迭代器,是Iterator的列表实现增强迭代器
此迭代器可以双向迭代
/*
测试类
*/
public class Application {
public static void main(String[] args){
//定义一个列表
List list = new ArrayList();
//按位置添加列表元素
list.add(0,new String("张三"));
list.add(0,new String("李四"));
list.add(0,new String("王五"));
list.add(0,new String("赵六"));
//获取列表迭代器
ListIterator listIterator = list.listIterator(0);
//向源列表位置0添加新元素,但不影响当前迭代
listIterator.add(new String("蒲七"));
//向后迭代
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
//向前迭代
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
//删除源列表中最后一个迭代的元素
listIterator.remove();
//更新源列表中最后一个迭代的元素
listIterator.set(new String("皮八"));
//打印列表
System.out.println(list.toString());
}
}
List方法
/*
测试类
*/
public class Application {
public static void main(String[] args){
//列表定义
List list = new ArrayList();
//按位置添加列表元素
list.add(0,new String("张三"));
list.add(0,new String("李四"));
list.add(0,new String("王五"));
list.add(0,new String("赵六"));
//按位置添加指定集合中元素
list.addAll(0,list);
//清除列表内容
list.clear();
//判断列表是否包含指定数据,利用相应Object的equals方法
list.contains(new String("张三"));
//判断列表是否包含指定集合中的数据,利用相应Object的equals方法
list.containsAll(list);
//获取指定位置的列表元素
list.get(0);
//返回列表中第一次出现指定元素的下标
list.indexOf(new String("张三"));
//判断列表是否为空
list.isEmpty();
//返回iterator迭代器
list.iterator();
//返回由列表指定位置后的全部元素的迭代器
list.listIterator(0);
//删除列表中指定位置的元素
list.remove(0);
//删除列表中指定集合的元素
list.removeAll(list);
//列表中只保留相应集合的元素
list.retainAll(list);
//更新列表中相应位置的元素
list.set(0,new String("秦七"));
//将列表转化为数组
list.toArray();
//返回源列表指定区间的新列表,左闭右开
list.subList(0, list.size());
//返回列表元素个数
list.size();
//打印列表
System.out.println(list.toString());
}
}
ArrayList
实现原理:数组
储存原理:
1、新加入对象,首先对于原本数组进行1.5倍扩容,然后存入数组尾部
Vector
实现原理:数组
LinkedList
实现原理:链表
储存原理:
1、新加入对象,将尾结点与新加入对象进行链接,然后更新尾结点
Set
简介
set集合为collection的子接口,称为无序集合
set集合元素特性:无序性、不可重复性
Set方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//定义set集合,hashset需要对象实现hashcode、equals方法
Set<String> set=new HashSet<>();
//集合添加元素,重复元素不会添加
set.add(new String("张三"));
set.add(new String("李四"));
set.add(new String("张三"));
//集合添加指定集合的元素,重复元素不添加
set.addAll(set);
//清除集合元素
set.clear();
//判断集合是否含有指定元素
set.contains(new String("张三"));
//判断集合是否含有指定集合的全部元素
set.containsAll(set);
//判断集合是否为空
set.isEmpty();
//返回集合迭代器
set.iterator();
//移除集合指定元素
set.remove(new String("张三"));
//移除集合中指定集合的全部元素
set.removeAll(set);
//集合仅仅保留指定集合的元素
set.retainAll(set);
//返回集合的元素个数
set.size();
//将集合转为数组
set.toArray();
//打印集合
System.out.println(set.toString());
}
}
HashSet
实现原理:数组+链表(哈希表)
不可重复性保证:hashcode方法、equals方法
储存原理:
1、对于所存入对象hashcode计算数组位置,如果相应位置无数据则储存,否则进入下一步
2、利用equals方法判断是否相等,相等则算作重复不进行储存,不相等则进行链表链接
3、底层使用hashmap的key进行实现
TreeSet
实现原理:红黑树
不可重复性保证:1、实现comparable接口并重写compareto方法 2、构造一个拥有comparator比较器的treeset
储存原理:
1、对于所存入对象compareto方法进行判断入树,相等不入树,不相等则入树
2、调整红黑树
3、底层使用treemap的key进行实现
Map
简介
Map是储存键值对的集合,K键非重复,V可重复
一个K映射一个V,Map就是映射关系的集合
Map方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//定义hashmap
Map<String,String> map = new HashMap<>();
//添加键值对
map.put(new String("S001"),new String("张三"));
map.put(new String("S002"),new String("李四"));
map.put(new String("S003"),new String("王五"));
map.put(new String("S004"),new String("赵六"));
//添加一个map
map.putAll(map);
//移除一个指定键值对
map.remove(new String("S002"),new String("张三"));
//清除所有数据
map.clear();
//判断是否存在相应key
map.containsKey(new String("S001"));
//判断是否存在相应values
map.containsValue(new String("张三"));
//判断是否为空
map.isEmpty();
//返回map数据个数
map.size();
//返回一个Map.Entry地图条目的Set
String s001 = map.get(new String("S001"));
Set<Map.Entry<String, String>> entries = map.entrySet();
//遍历Map.Entry地图条目的Set
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey()+"---"+entry.getValue());
}
//返回一个key的set
Set<String> strings = map.keySet();
//返回一个values的collcation集合
Collection<String> values = map.values();
System.out.println(map.toString());
}
}
HashMap
实现原理:数组+链表(哈希表)
不可重复性保证:hashcode方法、equals方法
储存原理:
1、对于所存入对象hashcode计算数组位置,如果相应位置无数据则储存,否则进入下一步
2、利用equals方法判断是否相等,相等则算作重复不进行储存,不相等则进行链表链接
TreeMap
实现原理:红黑树
不可重复性保证:1、实现comparable接口并重写compareto方法 2、构造一个拥有comparator比较器的treemap
储存原理:
1、对于所存入对象compareto方法进行判断入树,相等不入树,不相等则入树
2、调整红黑树
Java常用类
Object
简介
java所有类都实现了Object类,是所有类的超类
常用方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//定义object对象
Object o = new Object();
//对象比较方法
o.equals(o);
//返回对象哈希码
o.hashCode();
//将对象变成字符串
o.toString();
//返回Class对象
o.getClass();
//当前线程等待
o.wait();
//唤醒使用对象一个线程
o.notify();
//唤醒使用对象所有线程
o.notifyAll();
}
}
System
Scanner
简介
扫描输入流的扫描类。
常用方法
//构建键盘输入的扫描器类
Scanner scanner=new Scanner(System.in);
//整数输入例子
if (scanner.hasNextInt()) {//判断下一个输入的是不是int型
System.out.println("输入为:"+new Integer(scanner.nextInt()));//接收int型的输入
}
else {
System.out.println("输入的不是一个整数");
}
//关闭流
scanner.close();
注意点:
-scanner是输入流,查看源码可得知其是接受一个inputstream流进行构造
-scanner作为IO流,在不使用后必须进行关闭,否则会浪费资源
-scanner.hasNextXXX,判断下一次enter前是不是输入的XXX类型的数据
-scanner.nextXXX,返回下一次enter前输入的XXX型数据
-scanner.next返回的是有效字符后空格前的String
-scanner.nextLine,才是返回enter前的所有String(包括空字符串)
Arrays
简介
数组操作的工具类,其全部是静态方法。
常用方法
//预备数组
int[] a={12,45,11,889,1234,112,110,12};
//将数组转化为字符串
System.out.println(Arrays.toString(a));
//将数组进行升序排序,查看源码其对于不同长度数组进行不同的排序算法调用
Arrays.sort(a);
//使用二进制查找相应数组数据(第一次出现)的下标
System.out.println(Arrays.binarySearch(a,12));
//复制原数组的内容,并生成一个指定大小的数组,且生成的数组是进行了升序排序
int[] copyOf = Arrays.copyOf(a, a.length);
//对于数组进行全体赋值
Arrays.fill(a,0);
注:这里列举了部分方法
String
简介
java中表示字符串的类,字符串本身不可修改
String内部实现原理是字符数组
常用方法
/*
定义字符串
*/
//构造一个空字符的的字符串
String s1 = new String();
//利用一个字节数组,并设置相应的字符编码构造一个字符串
byte[] bytes=new byte[1024];
String s2 = new String(bytes,"UTF-8");
//利用一个字符数组的指定元素,构造一个字符串
char[] c1=new char[100];
String s3=new String(c1,0,99);
//利用字符缓冲区构造一个字符串
String s4 = new String(new StringBuffer());
//利用字符构造器构造一个字符串
String s5 = new String(new StringBuilder());
/*
常用方法
*/
//定义字符串
String s = new String("hello word!");
//返回指定位置的字符
s.charAt(0);
//按字符字典进行比较,返回比较结果
s.compareTo(new String("a"));
//返回一个在源字符串后添加一个字符串后的字符串
String concat = s.concat("i am fine!");
//判断字符串是否包括指定字符串序列
s.contains("hello");
//将XXX类型转化为String并返回String
String.XXXOf(XXX);
//返回一个指定编码格式的字节数组
byte[] bytes = s.getBytes("UTF-8");
//返回指定值出现的第一次的位置
s.indexOf(1);
//返回指定值出现的最后一次的位置
s.lastIndexOf(1);
//判断字符串大小是否为0
s.isEmpty();
//返回字符串大小
s.length();
//生成一个源字符串的指定序列字符串被替换为指定字符串后的的新字符串
String replaceAll = s.replaceAll("hello", "ok");
//返回源字符串指定区间的字符串,左闭右开
String substring = s.substring(0, s.length());
//字符串返回一个字符串数组
char[] chars = s.toCharArray();
StringBuffer
简介
stringbuffrer是java中用来处理字符串的一个工具类,其值允许改变,且线程安全。
其内部利用了缓存进行实现。我们操作这个类其实就是在对于这个缓存在进行操作。
常用方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
//生成stringbuffer对象,其默认容量为16,从其构造方法可以看出
StringBuffer buffer = new StringBuffer();
//向buffer中添加数据
buffer.append("hello word");
//返回buffer的容量
buffer.capacity();
//返回buffer中的字符个数
buffer.length();
//返回该位置的字符
buffer.charAt(3);
//删除buffer中一个区间的字符
buffer.delete(1,3);
//删除buffer中指定位置的字符
buffer.deleteCharAt(1);
//返回相应字符在buffer的位置
buffer.indexOf("a");
//向buffer中特定位置插入字符串
buffer.insert(1,"new");
//替代buffer特定区间的字符串
buffer.replace(0, buffer.length(), "new String");
//截取buffer中特定区间的字符串
buffer.substring(0,buffer.length());
//将缓冲区的数据进行字符串化
buffer.toString();
}
}
Date
简介
date类在java中表示日期与时间的类
常用方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
/*
获取当前时间创建date对象
分析源码可知构造时,使用的本地方法区的方法获取当前系统时间
*/
Date date = new Date();
/*
时间格式化对象用作时间的格式输出
y年
M月
d月的天
H一天的小时
h半天的小时
m小时的分钟
s分钟的秒数
*/
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd/hh/mm/ss");
//按照指定格式进行输出
System.out.println(simpleDateFormat.format(date));
}
}
Collcations
简介
collcations类是对于集合进行基本操作的工具类
常用方法
File
简介
File类是java对于文件或目录的操作类
File类与具体文件通过构造函数的参数(路径)进行了关联
常用方法
//创建一个File类,将一个文件或目录与File对象进行关联
File file = new File("D:\\test.txt");
//判断该文件是否可执行
file.canExecute();
//判断文件可写性
file.canWrite();
//判断文件可读性
file.canRead();
//判断该文件是否存在
file.exists();
//使用该文件对象,以对象的路径为依据创建一个文件
file.createNewFile();
//File类的工具,创建一个临时文件
File.createTempFile("qian","hou",new File("D:\\test"));
//删除该文件
file.delete();
//返回该文件的文件对象
file.getCanonicalFile();
file.getCanonicalFile();
//返回该文件的文件路径
file.getAbsolutePath();
file.getCanonicalPath();
//返回文件名字
file.getName();
//返回文件的目录
file.getParent();
//判断文件路径是否是绝对的
file.isAbsolute();
//判断文件是否为文件夹
file.isDirectory();、
//判断文件是否为文件
file.isFile();
//判断文件是否隐藏
file.isHidden();
//获取该文件最后修改时间
file.lastModified();
//获取改文件长度
file.length();
//获取该文件中的所有文件名
file.list();
//获取该文件中的所有文件
file.listFiles();
/*
文件重命名或移动,参数为需要转移到的新的File抽象
注:暂时测试跨盘失败
*/
file.renameTo(new File("D:\\newName.txt"));
//设置文件的可执行性
file.setExecutable(true);
//设置文件的最后修改时间
file.setLastModified(new Long(1));
//设置文件的可读性
file.setReadable(true);
//设置文件的只读
file.setReadOnly();
//设置文件的可写性
file.setWritable(true);
Class
简介
java中类的模板抽象类。
Class对象包含了一个Java类的所有信息。
ClassLoader
简介
Properties
简介
java中用来专门处理属性赋值的类。
properties类可以通过外部文件或者自行设置属性参数来进行相应的自定义属性赋值。
常用方法
/*
测试类
*/
public class Application {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
//1、将resource中的特定文件的属性加载到properties
properties.load(Test.class.getClassLoader().getResourceAsStream("test.properties"));
//2、直接对于properties属性进行设置
properties.setProperty("JAVA.SET","hello word");
//测试properties的属性是否记载成功
System.out.println("JAVA.SET: "+properties.getProperty("JAVA.SET"));
System.out.println("RESOURCE.SET: "+properties.getProperty("RESOURCE.SET"));
}
}