第一个JAVA程序
目录
public class HelloWorLd {//创建类
public static void main(String[] args) {//编写主函数
System.out.println("Hello World");//输出语句
/*
* public公开的
* class 类
* static静态的
* void 空的
*/
}
}
一 数据类型
1基本数据类型 ,2引用数据类型(1)类class (2)接口interface (3)数组[ ]
ps:一个Byte(字节)等于8个bit(位),bit是最小的单位,1B(字节)=8bit(位)。 一般情况下,一个汉字是两个字节,英文与数字是一个字节。
整数类型:byte,1字节,8位,最大存储数据量是255,存放的数据范围是-128~127之间。
整数类型:short,2字节,16位,最大数据存储量是65536,数据范围是-32768~32767之间。
整数类型:int,4字节,32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。
整数类型:long,8字节,64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
浮点类型:float,4字节,32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。
浮点类型:double,8字节,64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
字符型:char,2字节,16位,存储Unicode码,用单引号赋值。
布尔型:boolean,只有true和false两个取值A
类型转换
自动转换:只能最高级向下兼容
强制转换:(数据类型)表达式
会导致数据丢失
//自动转换
byte a= 10;
short b= a;
int c=b;
//强制转换
double d=15.15;
int e=(int)d;
System.out.println(c);//10
System.out.println(e);//15
二 运算符
算术运算符
+:加,—:减,*:乘,/:除,%:取余,
整数相除得整数,得小数需浮点数参与
“+"出现在字符串中是字符串连接符,
自增自减运算符
“++”“— —”
赋值运算符
“=":将等号右边的值赋值给左边的变量
扩展赋值运算符
”+=" 加后赋值:a+=b,a加b的值赋值给a
“—=”减后赋值,“*="乘后赋值,“\=”除后赋值,“%=”取余后赋值
关系运算符
"==":相等,“!=":不相等," >":大于,”>=":大于等于,“<”:小于,“<=”:小于等于
ps:成立为trut,不成立为false
逻辑运算符
“&“与:有false则false
”|"或:有trut则trut
“^”异:相同为false不同为trut
“!”非:双重否定为肯定
短路逻辑运算符
“&&”:有false则false,左边为假,右边不执行
“||”:有trut则trut,左边为真,右边不执行
int i=10;
int j=20;
int k=30;
int a=40;
//& :有false则false
System.out.println((i>j)&(i>k));
System.out.println((i<j)&(i>k));
System.out.println((i>j)&(i<k));
System.out.println((i<j)&(i<k));
//| :有true则true
System.out.println((i>j)|(i>k));
System.out.println((i<j)|(i>k));
System.out.println((i>j)|(i<k));
System.out.println((i<j)|(i<k));
//^:相同为false,不同为true
System.out.println((i>j)^(i>k));
System.out.println((i<j)^(i>k));
System.out.println((i>j)^(i<k));
System.out.println((i<j)^(i<k));
//!
System.out.println((i>j));
System.out.println(!(i>j));
System.out.println(!!(i>j));
//&&:有false则false,左边为假,右边不执行
System.out.println((i++>100)&&(j++<100));//false && false
System.out.println("i:"+i);//11
System.out.println("j:"+j);//20
//||:有trut则trut,左边为真,右边不执行
System.out.println((i++<100)&&(j++<100)||(k++>10)&&(a++>10));//true && true || false && false
System.out.println("i:"+i);//12
System.out.println("j:"+j);//21
System.out.println("k:"+k);//30
System.out.println("a:"+a);//40
//三元
System.out.println(i<j ? i:j);
三元运算符
关系表达式 ? 表达式1:l表达式2;
例:A>B ? A:B;
为trut表达式1为结果
为false表达式2为结果
三 输入语句
1在JAVA源代码类的上面引入Scanner类(导包),如下
import java.util.Scanner;
2在类里面实例化Scanner类,如下
Scanner input =new Scanner (System.in);
3调用next()方法或nextInt()方法接收用户输入的内容,然后赋值给指定变量,其中next()方法接收用户输入的字符串,nextInt()方法接收接收用户输入得整形数据, 如下
int stb=input.nextInt();
String name= input,next();
import java.util.Scanner;//导包
public class zhe {
public static void main(String[] args) {
Scanner input =new Scanner (System.in);//类里实例化Scanner类
System.out.println("请输入您的名字:");
String s1=input.next();//next()方法接收用户输入的字符串,
System.out.println("请输入您的年龄:");
int s2=input.nextInt();//nextInt()方法接收接收用户输入得整形数据,
}
}
四 选择语句
if 选择语句
格式:if(关系表达式){
语句体
}
执行流程:1:首先计算关系表达式的值
2:如果关系表达式的值为true就执行语句体
3:如果关系表达式的值为false就不执行语句体
4:继续执行后面的语句内容
System.out.println("开始");
int a=10;
int b= 20;
if (a==b){
System.out.println("a等于b");
}
int c=30;
if (a==c){
System.out.println("a等于c");
}
System.out.println("结束");
if语句二
格式:if(关系表达式){
语句体1
}eise{
语句体2
}
System.out.println("开始");
int a=10;
int b= 20;
if (a==b){//为true就执行语句体一,为false就执行语句体2
System.out.println("a等于b");
}else {
System.out.println("a不等于b");
}
System.out.println("结束");
if语句三
格式:if(关系表达式1){
语句体1
}else if(关系表达式1){
语句体2
}
,,,,,,,else{
语句体n+1
}
import java.util.Scanner;
public class jiangwan {
public static void main(String[] args) {
Scanner s1= new Scanner(System.in);
System.out.println("请输入一个星期书(1—7)");
int s2=s1.nextInt();
if (s2 ==1){
System.out.println("星期一");
}else if (s2 ==2){
System.out.println("星期二");
}else if (s2 ==3){
System.out.println("星期三");
}else if (s2 ==4){
System.out.println("星期四");
}else if (s2 ==5){
System.out.println("星期五");
}else if (s2 ==6){
System.out.println("星期六");
}else {
System.out.println("星期日");
}
System.out.println("结束");
}
}
switch 选择语句
格式:switch(表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2
break:
,,,,
default
语句体n+1;
[break]
}
import java.util.Scanner;
public class jiangwan {
public static void main(String[] args) {
Scanner s1= new Scanner(System.in);
System.out.println("请输入一个星期书(1—7)");
int s2=s1.nextInt();
switch(s2){
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("你输入的星期有误");
}
System.out.println("结束");
}
}
五 循环语句
循环结构
组成:
初始化语句:用于表示循环开启时的起始状态,这里可以时一条多条语句这些语句可以完成一些初始化操作。
条件判断语句:用于表示循环反复执行的条件,这里可以使用一个结果值为booolean类型的表达式这个表达式能决定是否执行循环体。例:a<3
循环体语句:用于表示循环反复执行的内容,这里可以是任意语句,这些语句将被反复执行。
条件控制语句:用于表示循环执行中每次变化的内容,这里通常是使用一条语句来改变汴梁的值从而达到是否继续向下执行的结果。常见 i++,i--。
1 for 循环语句
格式:
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
2 while 循环语句
格式:
初始化语句;
while(条件判断语句){
循环体语句;
条件控制语句;
}
3 do......while循环语句
格式:
初始化语句;
do{
循环体语句;
条件控制语句;
}while(条件判断语句);
//for循环
for (int i=1;i<=5;i++){
System.out.println("HelloWorld");
}
//while循环
int j=1;
while(j<=5){
System.out.println("HelloWorld");
j++;
}
//do,,while循环语句
int k=1;
do {
System.out.println("HelloWorld");
k++;
}while (k<=5);
三种循环区别
1:for循环和while循环先判断条件是否成立然后决定是否执行循环体(先判断后执行)
2:do,,while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)
for循环和while循环的区别
1:条件语句所控制是的自增变量,因为归属for循环的语句结构中,在for循环结束就不能再次被访问到了
2:条件语句所控制是的自增变量,对于while循环来说不归属语法结构中,while循环结束后仍然可一访问到并继续使用。
死循环格式:
for(;;){}
while(true){}
do{}while(true);
命令提示符窗口中Ctrl+c可以结束死循环
4 跳转控制语句
continue:用在循环中,基于条件控制,跳过某次循环体内容的执行,继续下次执行。
break:用在循环中,基于条件控制,终止循环体内容的执行,也就是说结束当前的整个循环。
for (int i=1;i<=5;i++){
if (i%2 == 0){
// continue;//输出 1,3,5
//break;//输出 1
}
System.out.println(i);
}
Random
作用:用于产生一个随机数
使用步骤:
1:导包
import java.util.Random;
2:创建对象
Random s =new Random();
3:获取随机数
int number =r,nextInt(10);
获取数据范围:(0,10)包括0,不包括10
import java.util.Random;
public class jiangwan {
public static void main(String[] args) {
Random a =new Random();
for (int i=0;i<10;i++){
int b=a.nextInt(10);
System.out.println("b:"+b);
}
int c =a.nextInt(100)+1;
System.out.println(c);
}
}
IDEA辅助键
快速生成main()方法:psvm,回车
快速生成输出语句:sout,回车
Ctrl+Ait+space(空格):内容提示,
Ctrl+Ait+v代码补全
单行注释:选中代码,Ctrl+/,再来一次取消
多行注释:选中代码,Ctrl+Shift+/,再来一次取消
格式化:Ctrl+Alt+l
六 数组
数组(array):一种用于存储多个相同类型数据的存储模型
定义格式:
1:数据类型[] 变量名(推荐)
例 int[] array
定义了一个int类型的数组,数组名是array
2:数据类型 变量名[]
例 int arr[]
定义了一个int类型的变量 变量名是arr数组
数组初始化
动态初始化:格式:数据类型[ 变量名=new 数据类型[数组长度]
动态初始化只指定数组长度,由系统为数组分配初始值
静态初始化:格式:数据类型[]变量名=new数据类型[]{数据1,数据2,,,}
静态初始化指定每个数组元素的初始值,由系统决定数组长度
/动态初始化
int[] arr1=new int[3];
//静态初始化
int[] arr2={1,2,3};
//访问
System.out.println(arr1);//[I@1b6d3586
System.out.println(arr1[0]);//0
System.out.println(arr1[1]);//0
System.out.println(arr1[2]);//0
ps:
索引越界:访问了数组中不存在的索引对应的元素
ArrayIndexOuOfbOunds Exception
空指针异常:访问的数组已经不再指向推内存的数据
Nullpointer Exception
null:空值,引用数据类型的默认值,表示不再指向任何有效对象
最小值
int[] arr2={13,14,24,12,53};
int max= arr2[0];
for (int i=1;i<arr2.length;i++){
if (arr2[i]<max){
max=arr2[i];
}
}
System.out.println(max);
遍历
int[] arr2={13,14,24,12,53};
for (int i=0;i<args.length;i++){//数组名,length :获取数组元素个数
System.out.println(args[i]);
}
七 方法
方法(method):是具有独立功能的代码组织成为一个整体,是其具有特殊功能的代码集
方法必须先创建才可以使用该过程成为方法定义
方法创建后需要手动使用才执行该过程称谓方法调用
方法定义:
定义格式:public static void 方法名(){
//方法体
}
调用格式:方法名();
方法必须先定义后调用,不能再main方法内定义方法
public class jiangwan {
public static void main(String[] args) {
ss();
}
public static void ss(){
int[] arr2={13,14,24,12,53};
int max= arr2[0];
for (int i=1;i<arr2.length;i++){
if (arr2[i]<max){
max=arr2[i];
}
}
带参数方法
方法定义格式:
public static void 方法名(参数){,,,,}
单个参数:public static void 方法名(数据类型 变量名){,,,,}
多个参数:public static void 方法名(数据类型 变量名1,数据类型 变量名2,,,,){,,,,}
调用格式:方法名(参数);
//常量值的调用
ss(10);//实参
//变量的调用
int number=11;//实参
ss(number);
}
public static void ss(int number){//形参
if ( number%2==0){
System.out.println(true);
}else {
System.out.println(false);
}
}
形参和实参
形参:方法定义中的参数
实参:方法调用中的参数
带返回值方法
定义格式:public static 数据类型 方法名(参数){
return 数据
}
调用格式:
1:方法名(参数);
2:数据类型 变量名 = 方法名(参数);
//方法名(参数)
ss(10);//实参
//数据类型 变量名 =方法名(参数)
boolean ff=ss(10);//实参
System.out.println(ff);
}
public static boolean ss(int number){//形参
if ( number%2==0){
return true;
}else {
return false;
}
方法重载
指同一个类中定义多个方法之间的关系满足下列条件的多个方法构成重载
1:多个方法在同一个类中
2:多个方法具有相同的方法名
3:多个方法的参数不相同,类型不同或者数量不同
public static void main(String[] args) {
System.out.println(ss(10,20));
System.out.println(ss(10,20));
System.out.println(ss(10,20,39));
}
public static int ss(int a,int b){
return a+b;
}
public static double ss(double a ,double b){
return a +b;
}
public static int ss(int a, int b,int c){
return a+b+c;
}
面向对象基础
一 类和对象
客观存在的事物皆为对象
类是对现实生活中具有共同属性和行为的事物的抽象
类是对象的抽象,对象是类的实体
类是对现实生活中一类具有共同属性和行为的事物的抽象确定对象将会拥有的属性和行为
类的特点
1:类是对象的数据类型
2:类是具有相同属性和行为的一组对象的集合
属性:对象具有的各种特征, 每个对象的内阁属性都拥有特定的值
在类中通过成员变量类体现
行为:对象能够执行的操作
在类中通过成员方法来体现
类的重要性:是Java的基本组成单位
类的定义:
定义类
编写成员变量
编写成员方法
对象的使用
创建对象
格式:类名 对象名=new 类名();
使用对象
1:使用成员变量
格式:对象名,变量名();
2:使用成员方法
格式:对象名,方法名();
public class jiangwan {
public static void main(String[] args) {
//创建对象
shuju a=new shuju();
//使用成员变量
a.brand="华为";
a.price=2000;
System.out.println(a.brand);
System.out.println(a.price);
//使用成员方法
a.call();
a.sendMessage();
}
}
public class shuju {
String brand;
int price;
public void call(){
System.out.println("打电话");
}
public void sendMessage(){
System.out.println("发短信");
}
}
成员变量和局部变量
成员变量:类中方法外的变量
局部变量:方法中的变量
二 封装
private关键字
1:是一个权限修饰符
2:可以修饰成员
3:作用是保护成员不被别的类使用,被private修饰的成员只在本类中才能访问
针对peivate修饰的成员变量如果需要被其他的类使用提供相应的操作
1:提供”get变量名()“方法,用于获取成员变量的值,方法用public修饰
2:提供”set变量名()“方法,用于设置成员变量的值,方法用public修饰
public class jiangwan {
public static void main(String[] args) {
shuju a =new shuju();
a.name="曹操";
a.setAge(-40);
a.show();
}
}
public class shuju {
//成员变量
String name;
private int age;
//提供get/set方法
public void setAge(int a){
//age=a;
if (a<0||a>100){
System.out.println("你给的年龄有误");
}else {
age=a;
}
}
public int getAge(){
return age;
}
//成员方法
public void show(){
System.out.println(name+","+age);
}
}
private关键字的使用
this关键字
1:方法的形参如果和成员变量同名,不带this修饰的变量指的是形参而不是成员变量
2:方法的形参没有与成员变量同名不带this修饰的变量指的是成员变量
this解决局部变量隐藏成员变量:方法被哪个对象调用,this就代表哪个对象
public class jiangwan {
public static void main(String[] args) {
//创建对象
shuju a=new shuju();
//使用set方法给成员赋值
a.setName("曹操");
a.setAge(30);
a.show();
//使用get方法获取成员变量的值
System.out.println(a.getName()+"--"+a.getAge());
System.out.println(a.getName()+","+a.getAge());
}
}
public class shuju {
//成员变量
private String name;
private int age;
//set/get方法
//public void setName(String n){
// name=n;
//}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int a){
age=a;
}
public int getAge(){
return age;
}
public void show(){
System.out.println(name+","+age);
}
}
封装概述:
是面向对象三大特征之一(封装,继承,多态)
是面向对象编程语言对世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
封装的原则
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供对应的getXxx()/setXxx()方法
封装好处
通过方法来控制成员变量恶的操作,提高了代码的安全性
把代码用方法进行封装,提高了代码的复用性
三 构造方法
构造方法是一种特殊的方法
作用:创建对象。功能:主要是完成对象数据的初始化
格式
public class 类名{
修饰符 类名 (参数){
}
}
public class shuju {
//成员变量
private String name;
private int age;
//构造方法
public shuju(){
System.out.println("无参构造方法");
}
public void show(){
System.out.println(name+","+age);
}
}
public class jiangwan {
public static void main(String[] args) {
shuju a=new shuju();//无参构造方法
a.show();//null,0
}
}
标准类:
public class shuju {
//成员变量
private String name;//成员变量使用private修饰
private int age;
//构造方法
public shuju(){}//提供一个无参构造方法
public shuju(String name,int age){//提供一个带多个参数的构造方法
this.name=name;
this.age=age;
}
//提供每一个成员变量对应的setXxx()/ getXxx()
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//提供一个显示对象信息的show()
public void show(){
System.out.println(name+","+age);
}
}
public class jiangwan {
public static void main(String[] args) {
//创建对象并为其它成员变量赋值的两种方式
//无参构造方法创建对象后使用setXxx()赋值
shuju s1=new shuju();
s1.setName("曹操");
s1.setAge(40);
s1.show();
///使用带参构造方法直接创建带有属性值的对象
shuju s2=new shuju("张三",18);
s2.show();
} }
四 String
String类在java.lang包下使用时不需要导包
String类代表字符串,java程序中所有字符串文字都被实现为此类的实例
也就是说java程序中所有双引号字符串,都是String类的对象
字符串的特点
1:字符串不可改变他们的值在创后不能被改变
2:虽然String的值时不可改变的但他们可以被共享
3:字符串效果是上相当于字符数组(charr[])但是底层原理时字节数组(byte[])
//public String():创建一个空白的字符串对象,不包含有任何内容
String s1=new String();
System.out.println("s1:"+s1);
//public String(char[] cgs):根据字符数组的内容来创建字符串对象
char[] chr ={'a','b','c'};
String s2=new String();
//public String (byte[] byt):根据字节数组的内容,来创建字符串对象
byte[] byt =[99,98,77];
String s3=new String(byt);
System.out.println("s3:"+s3);
//String s =“abc”:直接赋值的方式创建字符串对象 ,内容就是abc
String s4="ABC";
System.out.println("s4:"+s4);
字符串的比较
用“=="作比较
1:基本类型:比较的是数据值是否相同
2:引用类型:比较的是地址值是否相同
字符串比较内容是否相同通过一个方法来实现:equals()
public boolean equalse(object anobject):将此字符串与指定对象进行比较由于我们比较的是字符串对象,所以参数直接传递一个字符串
String中的方法
StringBuilder
StringBuilder是一个可变的字符串类,我们可以把它看成一个容器,这里的可变指的是StringBuilder对象的内容是可变的
String和StringBuilder的区别
String:内容是不可变的
StringBuilder:内容是可变的
StringBuilder的构造方法
//public StringBuilder()创建一个空白可变的字符串不含任何内容
StringBuilder s1=new StringBuilder();
System.out.println("s1:"+s1);
System.out.println("s1.length():"+s1.length());
//public StringBuilder(String str):根据字符串的内容来创建可变字符串对象
StringBuilder s2=new StringBuilder("Hello");
System.out.println("s2:"+s2);
System.out.println("s2.length:"+s2.length());
StringBuilder的添加和反转方法
//创建对象
StringBuilder s1=new StringBuilder();
//public StringBuilder append(任意类型)添加数据并返回对象本身
s1.append("hello").append("world").append("java");//链式编程
System.out.println("s1:"+s1);//s1:helloworldjava
//public StringBuilder reverse(): 返回相反的字符序列
s1.reverse();
System.out.println("s1:"+s1);//s1:avajdlrowolleh
StringBuilder和String相互转换
public String toString():通过toString()就可以实现吧StringBuilder转换为String
public
StringBuilder(String a):通过构造方法就可以实现把String转换为StringBuilder
//public String toString():通过toString()就可以实现吧StringBuilder转换为String
StringBuilder s1= new StringBuilder();
s1.append("Hello") ;
String s2=s1.toString();
System.out.println(s2);
//public StringBuilder(String a):通过构造方法就可以实现把String转换为StringBuilder
String SB="Woold";
StringBuilder s3=new StringBuilder(SB);
System.out.println(s3);
五 集合基础
集合类的特点:提供一种存储空间可变的存储模型,存储的数量容量可以发生改变
ArrayList(E)
1:可调整大小的数组实现
2:(E)是一种特殊的数据类型,泛型(出现E的地方使用引用数据类型替换
ArrayList集合
//public ArrayList():创建一个空的集合对象
//ArrayList<String> s1 =new ArrayList<>();
ArrayList<String> s1=new ArrayList<String>();
//public boolean add(E e):将指定的元素追加到此元素集合的末尾
System.out.println(s1.add("hello"));
s1.add("world");
s1.add("java");
//public void add(int index,E element):在此集合中的指定位置插入指定元素
s1.add(1,"javace");
//输出集合
System.out.println("s1:"+s1);
//public ArrayList():创建一个空的集合对象
//ArrayList<String> s1 =new ArrayList<>();
ArrayList<String> s1=new ArrayList<String>();
//添加元素
s1.add("hello");
s1.add("world");
s1.add("java");
//public boolean remove(object o):删除指定元素,返回删除是否成功
//System.out.println(s1.remove("world"));
//public E remove(int index):删除指定索引处的元素
// System.out.println(s1.remove(2));
//public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
//System.out.println(s1.set(2,"javace"));
//public E get (int index):返回指定索引处的元素
//System.out.println(s1.get(1));
//public int size():返回集合中元素的个数
//System.out.println(s1.size());
//输出集合
System.out.println("s1:"+s1);
六 继承
继承是面向对象的三大特征之一。可以使用子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法
格式:public class 子类名 extends 父类名{}
Fu:是父类 也叫基类,超类
Zi:子类,也叫派生类
特点:子类可以继承父类的方法,也能有自己的方法
继承的好处:
1:提高了代码的复用性
2:提高了代码的维护性
弊端:继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
Java中类只支持单继承,不支持多继承,支持多层继承
super
this:代表本类对象的引用
super:代表父类存储空间的标识(父类对象引用)
public class Fu {
public int age=40;
}
public class Zi extends Fu{
public int age=30;
public void show(){
int age=20;
System.out.println(age);
//访问本类中的age
System.out.println(this.age);
//访问父类中的age
System.out.println(super.age);
}
}
public class jiangwan {
public static void main(String[] args) {
Zi z=new Zi();
z.show();
} }
方法重写
概述:子类中出现和父类一模一样的方法声明
应用:当子类需要父类的功能,而功能主体子类有自己特定的内容时,可以重写父类中的方法这样既沿袭了父类的功能,又定义了子类特有的内容
方法重写注意事项:
1:私有方法不能被重写(父类私有成员子类是不能继承)
2:子类方法访问权限不能更低(public>默认>私有)
七 修饰符
包
其实就是文件夹,对类进行分类管理
定义格式:package 包名: (多级包用.分开)
导包
使用不同包下的类是要写类的全路径
为了简化了带包的操作,java就提供导包的功能
格式:import 包名;
权限修饰符:
状态修饰符
final
final 关键字是最终的意思,可以修饰成员方法,成员变量,类
final修饰的特点:
1:修饰方法:表明给方法是最终方法,不能被重写
2:修饰变量:表明该变量是常量,不能再次被赋值
3:修饰类:表明该类是最终类,不能被继承
final修饰局部变量
变量是基本类型:final修饰指的是基本类型的数据值不能发生改变
变量是引用类型:final修是指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的
static
static 关键字是静态的意思,可以修饰成员方法成员变量
static 修饰的特点
1:被类的所有对象共享(这是判断是否使用静态关键字的条件)
2:可以通过类名,对象名调用(推荐类名调用)
static访问特点
非静态的成员方法
能访问静态的成员变量
能访问非静态的成员变量
能访问静态的成员方法
能访问非静态的成员方法
静态的成员方法
能访问静态的成员变量
能访问静态的成员方法
(静态的成员方法只能访问静态的成员)
八 多态
同一个对象的,在不同时刻表现的不同形态
多态的前提和体现
1:有继承/实现关系
2:又方法重写
3:有父类引用指向子类对象
public class Fu {
public void ss(){
System.out.println("吃饭");
}
}
public class Zi extends Fu{//继承
@Override//重写
public void ss() {
System.out.println("喝水");
}
}
public class jiangwan {
public static void main(String[] args) {
//有父类引用指向子类对象
Fu a=new Zi();
} }
多态中成员访问特点
成员变量:编译看左边,执行看左边(父类没有则报错)
成员方法:编译看左边,执行看右边
成员方法有重写,成员变量没有
多态的好处和弊端
好处:
提高了程序的扩展性:定义方法的时候,使用父类型作为参数,在将来使用的时候使用具体的子类参与操作
弊端:不能使用子类的特有功能
多态中的转型
向上转型:
从子到父
父类引用指向子类对象
向下转型:
从父到子
父类引用转为子类对象
public class Fu {
public int age=40;
public void set(){
System.out.println("吃饭");
}
}
public class Zi extends Fu{
@Override
public void set() {
super.set();
}
public void play(){
System.out.println("玩");
}
}
public class jiangwan {
public static void main(String[] args) {
//有父类引用指向子类对象
Fu a=new Zi(); //向上转型
a.set();
//父类引用转为子类对象
Zi b= (Zi) a;
b.set();
b.play();
} }
九 抽象类
一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
抽象类的特点
1:抽象类和抽象方法必须使用abstract关键字修饰
public abstract class 类名{}
public abstract void 方法名()
2:抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
3:抽象类不能实例化:参照多态的方式,通过子类对象实例化,这叫抽象类多态
4:抽象类的子类,要么重写抽象类中的所有抽象方法,要么是抽象类
抽象类的成员方法
成员变量:可以是变量,也可以是常量
构造方法:有构造方法,但不能实例化:用于子类访问父类数据的初始化
成员方法:可以有抽象方法,限定子类必须完成某些动作
也可以有非抽象方法:提高代码复用性
十 接口
概述:接口就是一种公共的规范标准,java中的接口更多的体现在对行为的抽象
接口的特点
1:接口用关键字interface修饰
public interface jiekou {}
类实现接口用implements表示
public class 类名 implements 接口名{}
2:接口不能实例化
可以参照多态的方式,通过实现类对象实例化,这叫接口多态。
多态的前提是:有继承或者实现关系;有方法重写;有父类(类/接口)引用指向(子/实现)类对象
3:接口的实现类
要么重写接口中的所有抽象方法,要么是抽象类、
接口的成员特点
1:成员变量:只能是常量,默认修饰符:public static final
2:构造方法:接口没有构造方法,因为接口主要是对行为进行抽象,是没有具体存在
(一个类如果没有父类,默认继承Object)
3:成员方法:只能是抽象方法,默认修饰符:public abstract
public interface jiekou {
public int num=10;
public final int num2=20;
public static final int num3=30;
public abstract void show();
}
public class Zi implements jiekou{
@Override
public void show() {
}
public static void main(String[] args) {
jiekou a=new Zi();
System.out.println(a.num);
System.out.println(a.num2);
System.out.println(jiekou.num);
}
}
类和接口的关系
类和类:
继承关系,只能单继承,但是可以多继承
类和接口
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口和接口
继承关系,可以单继承,也可以多继承
抽象类和接口的区别
成员区别
抽象类 变量,常量;有构造方法;有抽象方法,也有非抽象方法
接口 常量; 抽象方法
关系区别
类与类 继承,单继承
类与接口 实现,可以单实现,也可以多实现
接口与接口 继承,单继承,多继承
设计理念区别
抽象类 对类抽象,包括属性,行为
接口 对行为抽象,主要是行为
类名作为形参和返回值
1:方法得形参是类名,其实需要的是该类的对象
2:方法的返回值是类名,其实返回的是该类的对象
public class Cat {
public void eat(){
System.out.println("猫吃鱼");
}
}
public class CatOperator {
public void useCat(Cat c){
c.eat();
}
public Cat getCat(){
Cat c =new Cat();
return c;
}
}
public class CatDemo {
public static void main(String[] args) {
//创建操作类对象
CatOperator co =new CatOperator();
Cat c=new Cat();
co.useCat(c);
Cat c2 =co.getCat();
c2.eat();
}
}
抽象类名作为参数和返回值
1:方法的形参是抽象类名,其实需要的是该类抽象类的子类对象
2:方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
public class CatOperator {
public void useCat(Cat c){//Cat c=new Cat()
c.eat();
}
public Cat getCat(){
Cat c =new xiaomao();
return c;
}
}
public abstract class Cat {
public abstract void eat();
}
public class xiaomao extends Cat{
@Override
public void eat() {
System.out.println("小猫喝奶");
}
}
public class CatDemo {
public static void main(String[] args) {
//创建操作类对象
CatOperator co =new CatOperator();
Cat c=new xiaomao();
co.useCat(c);
Cat c2= co.getCat();
}
}
接口作为形参和返回值
1:方法的形参是接口名,其实需要的是该接口的子类对象
2:方法的返回值是接口名,其实返回的是该接口的子类对象
package com.xd.oo;
public interface jumpping {
void jum();
}
package com.xd.oo;
public class jumppingOperator {
public void useJumpping(jumpping j){
j.jum();
}
public jumpping getJumpping(){
jumpping j =new Cat();
return j;
}
}
package com.xd.oo;
public class Cat implements jumpping{
@Override
public void jum() {
System.out.println("猫可以跳过了");
}
}
package com.xd.oo;
public class jumppingDemo {
public static void main(String[] args) {
jumppingOperator jo =new jumppingOperator();
jumpping j =new Cat();
jo.useJumpping(j);
jumpping j2=jo.getJumpping();
j2.jum();
}
}
十一 内部类
内部类:就是在一个类中定义一个类
举例:在一个类A的内部定义一个类B,类B就被称为内部类
定义格式:public class 类名{
修饰符 class 类名{
}}
按照内部类在类中定义的位置不同,可分为
1:在类的成员位置:成员内部类
2:在类的局部位置:局部内部类
匿名内部类
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
格式:new 类名或者接口名(){
重写方法
}
本质是一个继承了该类或者实现了该接口的子类匿名对象
public class jiangwan {
public int num =10;
public void method(){//方法
//匿名内部类
new inne(){
@Override
public void show() {
System.out.println("匿名内部类");
}
}.show();
inne a= new inne(){
@Override
public void show() {
System.out.println("匿名内部类");
}
};
a.show();
//局部内部类
class inner{
public void sh(){
System.out.println(num);
}
}
inner i =new inner();
i.sh();
//局部内部类外界无法直接使用需要在方法内部创建对象并使用,该类可以直接访问外部类的成员,
}
public class ss{//成员内部类
public void show(){
System.out.println(num);
}
}
}
public class Demo {
public static void main(String[] args) {
//成员内部类调用
jiangwan.ss oi=new jiangwan().new ss();
oi.show();
//局部内部类调用
jiangwan o=new jiangwan();
o.method();
}
}
十二 API
Math类
概述:Math包含执行基本数字运算的方法
类的成员是静态的可以1通过类名直接调用
//public static int abs(int a):返回参数的绝对值
System.out.println(Math.abs(88));
System.out.println(Math.abs(-88));
//public static double ceil(double a):返回大于或等于参数的最小doubli值,等于一个整数
System.out.println(Math.ceil(12.34));
System.out.println(Math.ceil(12.45));
//public static double floor(double a):返回小于或等于参数的最大double值,等于一个整数
System.out.println(Math.floor(12.34));
System.out.println(Math.floor(12.45));
//public static int round (flaat a):按照四舍五入返回最接近参数的int
System.out.println(Math.round(12.34F));
System.out.println(Math.round(12.56F));
//public static int max (int a,int b):返回两个int中的最大值
System.out.println(Math.max(34,56));
//public static int min (int a.int b):返回两个int中的最小值
System.out.println(Math.min(45,36));
//public static double pow (double a,double b):返回a 的b次幂
System.out.println(Math.pow(3,5));
//public static double random():返回值为double的正值,[0.0,1.0]
System.out.println(Math.random());
System
概述:System包含几个又要的类字段和方法,不能被实例化,通过类名访问
/*
System.out.println("开始");
//public static void exit(int ststus):终止当前运行的Java虚拟机,非零表示异常终止
System.exit(0);
System.out.println("结束");
*/
//public static long currentTimeMillis():返回当前时间,从1970年到现在(以毫秒为单位)
System.out.println(System.currentTimeMillis()*1.0/1000/60/60/24/365+"年");
//*1.0变为浮点数,365天24小时60分钟60秒1000毫秒
Object
object是类层次结构的根,每个类都可以将object作为超类,所有类都直接或间接继承自该类
构造方法:public object()
面向对象中,子类的构造方法默认访问的是父类的无参构造方法,因为它们的顶级父类只有无参构造方法
(看方法源码Ctrl+B)
获取字符串对象一般要重写Object中toString方法
equals方法也需重写
public class jiangwan {
private String name;
private int age;
public jiangwan() {
}
public jiangwan(String name,int age) {
this.name = name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {//重写toString
return "jiangwan{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {//重写equals方法
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
jiangwan jiangwan = (jiangwan) o;
if (age != jiangwan.age) return false;
return name != null ? name.equals(jiangwan.name) : jiangwan.name == null;
}
}
public class Demo {
public static void main(String[] args) {
jiangwan j =new jiangwan();
j.setName("曹操");
j.setAge(48);
System.out.println(j);//jiangwan@1b6d3586
jiangwan j2=new jiangwan();
j2.setName("曹操");
j2.setAge(48);
System.out.println(j.equals(j2));
}
}
Arrays
冒泡排序:一种排序方式,要对进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有的数据进行操作,直至所有数据按要求完成排序
public class Demo {
public static void main(String[] args) {
int[] arr={23,45,77,32,67};
System.out.println("排序前:"+arrayToString(arr));
for (int x =0;x<arr.length-1;x++){
for (int i=0;i<arr.length-1-x;i++){
if (arr[i]>arr[i]+1){
int temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
}
}
//把数组中的元素按照指定的规则组成一个字符串:【元素1,元素2,。。。】
private static String arrayToString(int[] arr) {
StringBuilder sb =new StringBuilder();
sb.append("【");
for (int i=0;i<arr.length ;i++){
if (i==arr.length-1){
sb.append(arr[i]);
}else {
sb.append(arr[i]).append(",");
}
}
sb.append("]");
String s=sb.toString();
return s;
}
}
nt[]arr={23,45,24,67,43};
System.out.println("排序前:"+ Arrays.toString(arr));
Arrays.sort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
工具类设计思想:
为了防止外界创建对象,构造方法用private修饰
为了使用类名来访问该成员方法,成员用public static 修饰
基本类型包装类
将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据
常用的操作之一:用于基本数据类型与字符串之间的转换
Integer类的概述和使用
Integer包装一个对象中的原始类型int的值
//public static Integer(int value):根据int值创建Integer 对象(过时)
Integer i1=new Integer(100);
System.out.println(i1);
//public Integer(String s):根据String值创建Integer对象(过时)
Integer i2=new Integer("100");
// Integer i2=new Integer("ABC");
System.out.println(i2);
//public static Integer valueOf(int i):返回表示指定的int 值的Integer实例
Integer i3=Integer.valueOf(100);
System.out.println(i3);
//public static Integer valueOf(String s): 返回一个保定指定的Integer对象String‘
Integer i4 = Integer.valueOf("100");
System.out.println(i4);
int 和String的相互转换
基本类型包装类的最常见操作就是:用于基本类型和字符串之间的相互转换
1:int 转换String
public static String valueOf(int i): 返回int参数的字符串表示形式,该方法是String类中的方法
2:String 转换int
public static int parselnt(String s):将字符串解析为int类型,该方法是Integer类中的方法
自动装箱和拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
//装箱
Integer i =Integer.valueOf(100);
// 自动装箱
Integer ii=100;
//拆箱
ii.intValue();
//自动拆箱
ii+=200;
ps;只要是对象,在使用前就必须进行不为null的判断
日期类
Date
Date代表了一个特定的时间,精确到毫秒
构造方法
SimpleDateFormat类
SimpleDateFormat是一个具体的类,用于以区域设置敏感的方格和解析日期
日期和时间格式由日期和时间模式字符指定,在日期和时间模式字符串中,从'A'到’Z'以及‘a’到‘z’的字母被解释为表示日期或时间字符串的组件的模式字母
常用的模式字母及对应关系
y---年
M--月
d--日
H--时
m--分
s--秒
构造方法
格式化和解析日期
1:格式化(从Date到String)
public final String format(Date date):将日期格式化成日期/时间字符串
2:解析(从String 到Date)
public Date parse (String source ):从给定字符串的开始解析文本以生成日期
Calendar类
Calender为某一时刻和一组日历字段之间的转换提供了一些方法,为操作日历字段提供了一些方法
Calender 提供了一个类方法getlnstance用于获取Calender,其日历字段已使用当前日期和时间初始化:
Calender rightNow =Calender.getlnstan();
十三 异常
异常:程序出现了不正常的情况
异常处理之try 。。。catch
格式:try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常处理的代码;
}
执行流程:程序从try里面开始执行,出现异常,会自动生成一个异常类对象,该异常类将被提交给java运行时系统
当Java运行时系统接收到异常类对象时,会到catch中去找匹配的异常类,找到后进行异常的处理
执行完毕之后,程序还可以继续往下执行
Throwable
Throwable是所有错误和异常的超类
public static void main(String[] args) {
System.out.println("开始");
menthod();
System.out.println("结束");
}
public static void menthod(){
try {
int[] arr={1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
// e.printStackTrace();
//public String getMessage():返回此throwable 的详细消息字符串
// System.out.println(e.getMessage());// 3 ??
//Index 3 out of bounds for length 3
// System.out.println(e.toString());//java.lang.ArrayIndexOutOfBoundsException: 3
//public void printStackTrace():把错误信息输出在控制台
e.printStackTrace();
}
}
编译时异常(受检异常):必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常(非受检异常):无需显示处理,也可以和编译时异常一样处理
RuntimeException类及其子类被称为运行时异常,其他的异常都是编译时异常
throws
格式:throws 异常类名;
注意:这个格式是跟在方法的括号后面的
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo {
public static void main(String[] args) {
System.out.println("开始");
menthod();
try {
method2();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("结束");
}
//编译时异常
public static void method2() throws ParseException {
String s="2021-11-19";
SimpleDateFormat sdf =new SimpleDateFormat();
Date d =sdf.parse(s);
System.out.println(d);
}
//运行时异常
public static void menthod() throws ArrayIndexOutOfBoundsException{
int[] arr={1,2,3};
System.out.println(arr[3]);
}
}
自定义异常
格式:public class 异常类名 extends Exceptyion{
无参构造
带参构造
}
public class jiangwan extends Exception{
public jiangwan(){ }
public jiangwan(String message){
super(message);
}
}
public class HelloWorLd {
public void checkScore(int score) throws jiangwan{
if (score<0||score>100){
//throw new jiangwan();
throw new jiangwan("你给的分数有误,分数应在1-100之间");
}else {
System.out.println("分数正常");
} }}
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
System.out.println("请输入分数");
int score =sc.nextInt();
HelloWorLd h =new HelloWorLd();
try {
h.checkScore(score);
} catch (jiangwan e) {
e.printStackTrace();
}
}
}
十四 集合进阶
Collection
概述:
1:是单例集合的顶层接口,他表示一组对象,这些对象也称为Collection的元素
2:JDK不提供此接口的任何直接实现,它提供更具体的子接口(Set和List)实现
创建Collection集合的对象
1:多态的方式
2:具体的实现类ArrayList
Collection集合常用方法
//创建Collection对象
Collection<String> c=new ArrayList<String>();
//boolean add(E e): 添加元素
c.add("hello");
c.add("world");
c.add("java");
//boolean remove(object o):从集合中移除指定元素
System.out.println(c.remove("java"));
//void clear():清空集合中的元素
//c.clear();
//boolean contains(object o):判断集合中是否有指定的元素
System.out.println(c.contains("hello"));
System.out.println(c.contains("javace"));
//boolean isEmpty():判断集合是否为空
System.out.println(c.isEmpty());
//int size():集合的长度,也就是集合中元素的个数
System.out.println(c.size());
//输出集合对象
System.out.println(c);
iterator:迭代器,集合的专用遍历方式
1:iterator<E>iterator():返回此集合中的迭代器,通过集合的iterator()方法得到
2:迭代器是通过集合iterator()方法得到的,所以我们说它是依赖于集合而存在的
iterator中的常用方法
1:E next():返回迭代中的下一个元素
boolean hasNext():如果迭代具有更多元素,则返回true
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo {
public static void main(String[] args) {
//创建Collection对象
Collection<String> c=new ArrayList<String>();
c.add("hello");
c.add("world");
c.add("java");
//Iterator<E> iterator():返回此集合中的迭代器,通过集合iterator()方法得到
Iterator<String> it = c.iterator();
while (it.hasNext()){
String s=it.next();
System.out.println(s);
}
}
}
Lise集合
概述:
1:有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
2:与Set集合不同,列表通常允许重复的元素
Lise集合特点
1:有序:存储和取出的元素顺序一致
2:可重复:存储的元素可以重复
List集合特有方法
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo {
public static void main(String[] args) {
//创建对象
List<String> lise = new ArrayList<String>();
//添加元素
lise.add("hello");
lise.add("world");
lise.add("java");
lise.add("hello");
// //void add(int index):在此集合中的指定位置插入指定的元素
// lise.add(2,"javace");
// //E remove (int index):删除指定索引处的元素,返回被删除的元素
// System.out.println(lise.remove(3));
// //E set (int index,E element):修改指定索引处的元素,返回被修改的元素
// System.out.println(lise.set(3,"javaee"));
// //E get (int index):返回指定索引处的元素
// System.out.println(lise.get(1));
// //输出集合对象
// System.out.println(lise);
// //迭代器
Iterator<String> it= lise.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
// }
for (int i=0;i<lise.size();i++){
String s=lise.get(i);
System.out.println(s);
}
}
}
ListIterator
listlteretor:列表迭代器
1:通过List集合的listerator()方法得到,所以说它是List集合特有的迭代器
2:用于允许程序员沿任何以方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
Listlterator中常用方法
E next():返回迭代中的下一个元素
BooleanhasNext():如果迭代具有更多元素,则返回true
E previous():返回列表中的上一个元素
boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
void add(E e):指定的元素插入列表
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Demo {
public static void main(String[] args) {
//创建对象
List<String> lise = new ArrayList<String>();
//添加元素
lise.add("hello");
lise.add("world");
lise.add("java");
//通过list集合的listIterator()方法得到
// ListIterator<String> lit = lise.listIterator();
// while (lit.hasNext()){
// String s = lit.next();
// System.out.println(s);
// }
// System.out.println("---------");
// //反方向遍历
// while (lit.hasPrevious()){
// String s = lit.previous();
// System.out.println(s);
// }
ListIterator<String> lit = lise.listIterator();
while (lit.hasNext()){
String s = lit.next();
if (s.equals("world")){
lit.add("javacc");
}
}
}
}
增强for循环
增强for:简化数组和Collection集合的遍历
1:实现Iterable接口的类允许其对象成为for语句的目标
2:它是JDK5之后出现的,其内部原理是一个Iterator语句的目标
增强for的格式:
for(元素数据类型 变量名:数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
int[]arr={1,2,3,4,5};
for (int i:arr){
System.out.println(i);
}
System.out.println("-------");
String[] str={"hello","world","java"};
for (String s:str){
System.out.println(s);
}
System.out.println("-------");
List<String> List = new ArrayList<>();
List.add("Hello");
List.add("World");
for (String s2:List){
System.out.println(s2);
}
}
}
三种遍历
public class jiangwan{
private String name;
private int age;
public jiangwan() {
}
public jiangwan(String name,int age) {
this.name = name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<jiangwan> arr = new ArrayList<>();
jiangwan s1 = new jiangwan("张三",18);
jiangwan s2 = new jiangwan("李四",19);
jiangwan s3 = new jiangwan("王五",19);
arr.add(s1);
arr.add(s2);
arr.add(s3);
//迭代器
Iterator<jiangwan> it = arr.iterator();
while (it.hasNext()){
jiangwan s = it.next();
System.out.println(s.getName()+","+s.getAge());
}
System.out.println("--------");
//普通for循环,带索引
for (int i=0;i<arr.size();i++){
jiangwan s = arr.get(i);
System.out.println(s.getName()+","+s.getAge());
}
System.out.println("--------");
//增强for循环,最方便
for (jiangwan j:arr){
System.out.println(j.getName()+","+j.getAge());
}
}
}
List集合子类特点
Lidt集合常用的子类:ArrayLst,LinkedList
ArrayLst:底层数据结构是数组,查询快,增删慢
LinkedList:底层数据结构是链表,查询慢,增删快
LinkedList集合中的特有功能
import java.util.LinkedList;
public class Demo {
public static void main(String[] args) {
LinkedList<String> linke = new LinkedList<>();
linke.add("hello");
linke.add("world");
linke.add("java");
//public void addFirst(E e):在该列表开头插入指定的元素
//public void addLast(E e):将指定的元素追加到此列表的末尾
linke.addFirst("IT");
linke.addLast("javaee");
//public E getFirst():返回此列表中第一个元素
//public E getLast():返回此列表中最后一个元素
System.out.println(linke.getFirst());
System.out.println(linke.getLast());
//public E removeFirst():从此列表中删除返回第一个元素
//public E removalast():从此列表中删除返回最后一个元素
System.out.println(linke.removeFirst());
System.out.println(linke.removeLast());
System.out.println(linke);
}
}
Set集合
特点:
1:不包含重复元素的集合
2:没有带索引得方法,所以不能使用普通for循环遍历
哈希值
哈希值:是JDK根据对象得地址或者字符串或者数字算出来得int类型的数值
object类中有一个方法可以获取对象的哈希值
public int hashCode():返回对象的哈希码值
1:同一个对象多次调用hashCode()方法返回的哈希值是相同的
2:默认情况下,不同对象的哈希值是不同的,而重写hashCode()方法,可以实现让不同对象的哈希值相同
HashSet集合特点
1:底层数据结构是哈希表
2:对集合的迭代顺序不做任何保证,不保证存储和取出的元素顺序一致
3:没有带索引的方法,所以不能使用普通for循环遍历
4:由于是Set集合,所以是不包含重复元素的集合
LinkedHashSet集合
LinkedHashSet集合特点
1:哈希表和链表实现的Set接口,具有可预测的迭代次序
2:有链表保证元素有序,
3:有哈希表保证元素唯一,
TreeSet集合特点
1:元素,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据器元素的自然排序进行排序
TreeSet(C欧美怕让投入comparator):根据指定的比较器进行排序
2:没有带索引的方法,所以不能是使用普通for循环
3:由于是Set集合所以不包含重复元素的集合
自然排序
1:TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序
2:自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法
3:重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
public class jiangwan implements Comparable<jiangwan>{
private String name;
private int age;
public jiangwan() {
}
public jiangwan(String name,int age) {
this.name = name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(jiangwan s) {
//return 0;//重复元素不添加
//return 1;升序
// return -1;降序
int num= this.age-s.age;//this在前升序
int num2=num==0?this.name.compareTo(s.name):num;
return num2;
}
}
import java.util.LinkedHashSet;
import java.util.TreeSet;
public class Demo {
public static void main(String[] args) {
TreeSet<jiangwan> ts = new TreeSet<jiangwan>();
jiangwan j1= new jiangwan("wangzhaojun",23);
jiangwan j2 = new jiangwan("xishi",30);
jiangwan j3 = new jiangwan("yangyuhuan",26);
jiangwan j4 = new jiangwan("diaochan",20);
jiangwan j5=new jiangwan("zhongrenmincai",20);
ts.add(j1);
ts.add(j2);
ts.add(j3);
ts.add(j4);
ts.add(j5);
for (jiangwan j:ts){
System.out.println(j.getName()+","+j.getAge());
}
}
}
比较器排序Comparator的使用
1:TreeSet集合存储自定义对象,无参构造方法使用的是比较器排序对元素进行排序
2:比较强排序,就是让集合构造方法接收Comparable的实现类对象,重写compareTo(To)方法
3:重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
public class jiangwan{
private String name;
private int age;
public jiangwan() {
}
public jiangwan(String name,int age) {
this.name = name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.util.Comparator;
import java.util.TreeSet;
public class Demo {
public static void main(String[] args) {
TreeSet<jiangwan> ts = new TreeSet<>(new Comparator<jiangwan>() {
@Override
public int compare(jiangwan o1, jiangwan o2) {
int num =o1.getAge()-o2.getAge();
int num2=num==0?o1.getName().compareTo(o2.getName()):num;
return 0;
}
});
jiangwan j1= new jiangwan("wangzhaojun",23);
jiangwan j2 = new jiangwan("xishi",30);
jiangwan j3 = new jiangwan("yangyuhuan",26);
jiangwan j4 = new jiangwan("diaochan",20);
jiangwan j5=new jiangwan("zhongrenmincai",20);
ts.add(j1);
ts.add(j2);
ts.add(j3);
ts.add(j4);
ts.add(j5);
for (jiangwan j:ts){
System.out.println(j.getName()+","+j.getAge());
}
}
}
泛型
概述:是JDK5中引入的特性,他提供了编译时类型安全检测机制,该机制运许在编译时检测到非法的类型,本质是参数化类型,也就是说所说操作的数据类型被指定为一个参数
参数化类型:将类型由原来的具体类型参数化,然后在使用/调用时传入具体的类型
这种参数类型可以用在类,方法,和接口中。分别称为泛型类,泛型方法,泛型接口
定义格式:
1:<类型>:指定一种类型的格式,这里的类型可以看成形参
2:<类型1,类型2,....>:指定多种类型的格式,多种类型之间用逗号隔开,这里可以看成形参
3:将来具体调用时候给定的类型可以看成实参,并且实参的类型只能是引用数据类型
泛型的好处:
把运行时期的问题提前到编译期间
避免了强制类型转换
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo {
public static void main(String[] args){
//Collection c=new ArrayList();
Collection<String> c=new ArrayList<String>();
c.add("hello");
c.add("world");
c.add("java");
// Iterator it =c.iterator();
Iterator<String> it =c.iterator();
while (it.hasNext()){
// Object obj = it.next();
// System.out.println(obj);
// String s=(String) it.next();
String s = it.next();
System.out.println(s);
}
}
}
泛型类
定义格式:修饰符 class 类名<类型>{}
例:public class Generic<T>{}
此处T可以随便写为任意标识,常见的如T,E,K,V等形式的参数常用于表示泛型
public class jiangwan<T>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public class Demo {
public static void main(String[] args){
jiangwan<String> j1=new jiangwan<>();
j1.setT("张楚岚");
System.out.println(j1.getT());
jiangwan<Integer> j2=new jiangwan<Integer>();
j2.setT(20);
System.out.println(j2.getT());
}
}
泛型方法
public class jiangwan{
public <T> void show(T t){
System.out.println(t);
}
}
public class Demo {
public static void main(String[] args){
jiangwan j=new jiangwan();
j.show("张之维");
j.show(120);
j.show(true);
}
}
泛型接口
定义格式:修饰 interface 接口名 <类型>{}
public interface inne <T>{
void show(T t);
}
public class jiangwan<T> implements inne<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}
public class Demo {
public static void main(String[] args){
inne<String> i=new jiangwan<String>();
i.show("无根生");
inne<Integer> j2=new jiangwan<Integer>();
j2.show(100);
}
}
类型通配符
为了表示各种泛型List的父类可以使用类型通配符
1:类型同配符:<?>
List<?>表示元素类型未知的List,它的元素可以匹配任何的类型
这种通配符得Lise仅表示它是各种泛型得父类,并不能把元素添加到其中
2:如果我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型的父类,可以使用类型通配符的上限
类型通配符:<?extends 类型>
LIstanbul<? extends Number>:他代表的类型是Number或者其子类类型
3:除了可以指定类型通配符的上限,也可以指定类型通配符的下限
类型通配符下限:<?super 类型>
List <? super Number>:它表示的类型是Number或者其父类类型
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args){
//类型通配符
List<?> list1=new ArrayList<Object>();
List<?> list2=new ArrayList<Number>();
List<?> list3=new ArrayList<Integer>();
//类型通配符上限:<?extends 类型>
List<? extends Number> list5=new ArrayList<Number>();
List<? extends Number> list6=new ArrayList<Integer>();
//List<? extends Number> list7=new ArrayList<Object>();
//通配符下限:<? super 类型>
List<? super Number> list7=new ArrayList<Object>();
List<? super Number> list8=new ArrayList<Number>();
// List<? super Number> list9=new ArrayList<Integer>();
}
}
可变参数
可变参数又称个数可变,用作方法的形参出现,那么方法参数个数就是
格式:修饰符 返回值类型方法名(数据类型...变量名)
注意:
这里的变量其实是一个数组
如果一个方法有多个参数,包含可变参数,可变参数要放在最后
public class Demo {
public static void main(String[] args){
System.out.println(sum(10,20));
System.out.println(sum(10,20,30));
System.out.println(sum(10,20,30,40));
System.out.println(sum(10,20,30,40,50));
System.out.println(sum(10,20,30,40,50,60));
System.out.println(sum(10,20,30,40,50,60,70));
}
public static int sum(int...a){
//return 0;
int sum =0;
for (int i:a ){
sum+=i;
}
return sum;
}
}
可变参数的使用
Arrays工具类中有一个静态方法:
public static <T> List<T> asList(T...a):返回有指定数组支持的固定大小
List接口中有一个静态方法:
public static <E>List <E> of(E...elements):返回包含任意数量元素的不可变列表
Set接口中有一个静态方法:
public static <E>Set<E> of (E ...elements):返回一个任意数量元素的不可变集合
//public static <T> List<T> asList(T...a):返回有指定数组支持的固定大小
List<String> list = Arrays.asList("hello", "world", "java");
// list.add("javaee");//UnsupportedOperationException
// list.remove("world");//UnsupportedOperationException
list.set(1,"jacacc");
Map
概述:
1:Interface Map<K ,V> k:键的类型 v:值得类型
2:将键映射到值得对象;不能包含重复得键;每个键可以映射到最多一个值
创建Map集合得对象
1:多态得方式
2:具体得实现类HashMap
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args){
Map<String,String> map =new HashMap<String,String>();
//V put (k key,v value):添加元素
map.put("2021001","冯宝宝");
map.put("2021002","张楚岚");
map.put("2021003","王也");
//V remove(Object key):根据键删除键值对元素
System.out.println(map.remove("2021003"));
//void clear():移除所有的键值对象
// map.clear();
//boolean containsKey(Object key):判断集合是否包含指定的键
System.out.println(map.containsKey("2021002"));
//boolean isEmpty():判断集合是否为空
System.out.println(map.isEmpty());
//boolean size():集合的长度,也就是集合的个数
System.out.println(map.size());
System.out.println(map);
}
}
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo {
public static void main(String[] args){
Map<String,String> map =new HashMap<String,String>();
//V put (k key,v value):添加元素
map.put("2021001","冯宝宝");
map.put("2021002","张楚岚");
map.put("2021003","王也");
//V get (Object key):根据键的值获取值
System.out.println(map.get("2021001"));
System.out.println(map.get("2021002"));
// //Set<K> keySey():获取所有值的集合
// Set<String> keySey=map.keySet();
// for (String key:keySey){
// System.out.println(key);
// }
//Collection<V> values():获取所有值的集合
Collection<String> values=map.values();
for (String value:values){
System.out.println(value);
}
}
}
Map集合遍历
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo {
public static void main(String[] args){
Map<String,String> map =new HashMap<String,String>();
map.put("2021001","冯宝宝");
map.put("2021002","张楚岚");
map.put("2021003","王也");
// Set<String> keySey=map.keySet();
//
// for (String key:keySey){
// String value=map.get(key);
// System.out.println(key);
// }
Set<Map.Entry<String,String>> entrySetSet=map.entrySet();
for (Map.Entry<String,String> mw:entrySetSet){
String key=mw.getKey();
String value=mw.getValue();
System.out.println(key+"."+value);
}
}
}
Collection
概述:
是针对集合操作的工具类
常用方法
public static <T extends Comparble<?super T>> void sort(List<T>list):将指定的列表按升序排序
public static void reverse(List <?>list):反转指定列表中的元素的顺序
public static void shuffle(List<?>list):使用默认的随机源随机排列指定的列表
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo {
public static void main(String[] args){
List<Integer>list=new ArrayList<Integer>();
list.add(20);
list.add(30);
list.add(10);
list.add(40);
//public static <T extends Comparble<?super T>> void sort(List<T>list):将指定的列表按升序排序
// Collections.sort(list);
//public static void reverse(List <?>list):反转指定列表中的元素的顺序
//Collections.reverse(list);
//public static void shuffle(List<?>list):使用默认的随机源随机排列指定的列表
Collections.shuffle(list);
System.out.println(list);
}
}
十五 IO流
IO流概述:
1:IO:输入/输出(Input/Output)
2:流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输
3:IO流就是用来处理设备间数据传输问题的
常见的应用:文件复制,文件上传,文件下载
IO流分类;
1;按照数据的流向(默认)
输入流:读数据
输出流:写数据
2:按照数据类型来分
字节流
字节输出流;字节输入流
字符流
字符输出流;字符输入流
ps:如果数据通过window自带的记事本打开,可以读懂内容。就使用字符流
否则使用字节流,如果你不知道使用哪种流,就使用字节流
File
File:它是文件和目录路径名的抽象表示
1:文件和目录是可以通过File封装成对象的
2:对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,它可以是存在的,也可以是不存在的,将来时要通过具体的操作把这个路径的内容转换为具体存在
File构造方法
递归
概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象
递归解决问题的思路:
把一个复杂问题层层转化为一个与原问题相似的规模较小的问题来求解
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
递归解决问题要找到两个内容
递归出口:否则会出现内存溢出
递归规则:与原问题相似的规模较小的问题
public class Demo {
public static void main(String[] args){
int re=jc(5);
System.out.println("5的阶乘是"+re);
}
public static int jc(int n){
if (n==1){
return 1;
}else {
return n*jc(n-1);
}
}
}
字节流
字节流抽象基类
InoutStream:这个抽象类是表示字节输出流的所有超类
OutputStram:这个抽象类是表示字节流输出的所有类的超类
子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream:文件输出流用于将数据写入File
FileOutputStream(String name):创建文件输出流以指定的名称写入文件
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//FileOutputStream(String name):创建文件输出流以指定的名称写入文件
FileOutputStream dor = new FileOutputStream("dor.txt");
/*
做了三件事
1:调用系统功能创建了文件
2:创建了字节输出流对象
3:让字节输出流对象指向创建的文件
*/
//FileOutputStream:文件输出流用于将数据写入File
dor.write(97);
//IO流最后都要释放资源
//void close ():关闭文件输出流并释放与此流相关的任何系统资源
dor.close();
}
}
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
FileOutputStream dor = new FileOutputStream("dor.txt ");
//void write(int b):将指定的字节写入此文件输出流
dor.write(101);
//
// //void write (byte[] b):将b.length字节从指定的字节数组写入此文件输出流
// byte[]byt ={101,100,99,98,97};
// dor.write(byt);
// //byte[]getBytes:返回字符串对应的字节数组
byte[] by = "abcdef".getBytes();
// dor.write(by);
//void write (byte[] b,int off,int len):将len字节从指定的数组开始,从偏移量off开始写入次文件输出流
dor.write(by,1,4);
//释放资源
dor.close();
}
}
字节流写数据换行
写完加换行符
windows:\r\n
linux:\n
mac:\r
字节流写数据追加写入
public FileOutoutStream(String name,boolean append)
创建文件输出流以指定的名称写入文件,第二个参数为true ,字节将写入文件的末尾而不是开头
字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有清楚操作,比如IO流中的释放资源
特点:被finally控制的语句一定会执行,除非JVM退出
格式:try{
可能出现的异常的代码
}catgh{
异常的处理代码
}finall{
执行所有清除操作
}
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args){
FileOutputStream dor=null;
try {
dor=new FileOutputStream("D\\dre");
}catch (IOException e){
e.printStackTrace();
}finally {
try {
dor.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
字节流读数据
FileInputStream:从文件系统中的文件获取输入字节
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径name命名
一次读一个字节:
import java.io.FileInputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream fie=new FileInputStream("dor.txt");
//读数据
// int by=fie.read();
// System.out.println(by);
// System.out.println((char) by);
//优化1
/*
int by=fie.read();
while (by !=-1){
System.out.print((char) by);
by=fie.read();
}*/
//优化2
int by;
while ((by=fie.read())!= -1){
System.out.print((char) by);
}
fie.close();
}
}
字节流读数据一次读一个字节数组:
import java.io.FileInputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream fie=new FileInputStream("dor.txt");
/* byte[] bys=new byte[5];
//第一次读取数据
int len=fie.read(bys);
System.out.println(len);
System.out.println(new String(bys,0,len));
//第一次读取数据
len=fie.read(bys);
System.out.println(len);
System.out.println(new String(bys,0,len));
*///改进
byte[] byt=new byte[1024];
int len;
while ((len=fie.read(byt))!=-1){
System.out.println(new String(byt,0,len));
}
fie.close();
}
}
字节流缓冲流
字节缓冲流:
BufferOutputStream:该类实现缓冲输出流,通过设置这样的输出流,应用程序,可以向底层输出流写入字节,而不必为写入的没格子节导致底层系统的调用
BufferedlnputStream: 创建BufferedlnputStream将创建一个内部缓冲区数组。当从流中读取或者跳过字节时,内部缓冲区将根据需要从所包含的输出流中重新填充,一次很多字节
构造方法:
字节缓冲输出流:BufferedOutputStream(OutputStream out)
字节缓冲输入流:BufferedlnputStream(lnoutStream in)
字节缓冲流仅仅提供缓冲区,而真正的读取数据还得依靠基本的字节流对象进行操作
import java.io.*;
import java.nio.charset.StandardCharsets;
public class Demo {
public static void main(String[] args) throws IOException {
//字节缓冲输出流:BufferedOutputStream(OutputStream out)
// FileOutputStream fos=new FileOutputStream("dor.txt");
// BufferedOutputStream dos=new BufferedOutputStream(fos);
// BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("dor.txt"));
// //写数据
// bos.write("hello\r\n".getBytes());
// bos.write("world\r\n".getBytes());
// //释放资源
// bos.close();
//字节缓冲输入流:BufferedInputStream(InoutStream in)
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("dor.txt"));
//一次读取一个字节数组
//
//一次读取一个字节数组数据
byte[] bys=new byte[1024];
int len;
while ((len=bis.read(bys))!=-1){
System.out.println(new String(bys,0,len));
}
bis.close();
}
}
字符流
字符流=字节流+编码表
import java.io.*;
public class Demo {
public static void main(String[] args) throws IOException {
//OutputStreamWriter(OutputStream out):创建一个使用默认字符编码集的outputStreamWriter
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("osw.txt"));
//void write(int c):写一个字符
// osw.write(98);
// osw.flush();//刷新流
// osw.write(99);
//void write(char cbuf):写入一个字符数组
char[] chr={'a','b','c','d','e'};
// osw.write(chr);
//void write (char[] cbuf,int off, int len):写入字符数组的一部分
// osw.write(chr,0,chr.length);
// osw.write(chr,0,2);
//void write(String str):写一个字符串
// osw.write("sdfg");
//void write (String str ,int off,int len):写一个字符串的一部分
//osw.write("abcde",0"abcde".length());
osw.write("abcde",1,3);
osw.close();//先刷新再释放
}
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class Demo {
public static void main(String[] args) throws IOException {
//InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader
InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"));
//int read():一次读一个字符数组
// int ch;
// while ((ch=isr.read())!=-1){
// System.out.println((char) ch);
// }
//int read(char[]cbuf):一次读一个字符数组数据
char[] chr=new char[1024];
int len;
while ((len=isr.read(chr))!=-1){
System.out.println(new String(chr,0,len));
}
//释放资源
isr.close();
}
}
字符缓冲流
1:BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符堵塞高效写入,可以指定缓冲区大小,或者可以接收默认大小默认值足够大,可用于大多数用途
2:BufferedReader:从字符输出流读取文本,缓冲字符,以提供字符,数组和高效读取,可以指定缓冲区大小、。或者使用默认大小,默认值足够大,可用于大多数用途
构造方法
BufferedWriter(Writer out)
BufferedReader(Reader)
字符缓冲流的特有功能
BufferedWriter:
void newLine():写一个行行分隔符,行分隔符字符串由系统属性定义
BufferedReader
public String readLinne():读一行文字,结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达。则为null
import java.io.*;
public class Demo {
public static void main(String[] args) throws IOException {
//BufferedWriter(Writer out)
// FileWriter fw=new FileWriter("bw.txt");
// BufferedWriter bw=new BufferedWriter(fw);
// BufferedWriter by=new BufferedWriter(new FileWriter("osw.txt"));
// for (int i=0;i<10;i++){
// by.write("hello"+i);
// by.newLine();//换行
// by.flush();//刷新
// }
// by.close();
//BufferedReader(Reader)
BufferedReader dr=new BufferedReader(new FileReader("osw.txt"));
//一次读取一个字节
// int ch;
// while ((ch=dr.read())!=-1){
// System.out.println((char) ch);
// }
//一次读取一个字符数组数据
// char[] chs=new char[1024];
// int len;
// while ((len=dr.read())!=-1){
// System.out.println(new String(chs,0,len));
// }
String line;
while ((line=dr.readLine())!=null){
System.out.println(line);
}
//释放资源
dr.close();
}
}
操作流
标准输入输出流
System类中有两个静态的成员变量:
public static final InpuStream in:标准输出流,通常该流对应于键盘输出或者由主机环境或用户指定的另一个输入源
public static final PrintStresm out:标准输出流, 通常该流对应于显示输出或者由主机环境或用户指定的另一个输出目标
打印流
分类
字节打印流:PrintStream
字符打印流:PrintWriter
打印流特点:
只负责输出数据,不负责读取数据
有自己的特有方法
字节打印流
PrintStream(String fileName):使用指定文件名创建新的打印流
使用继承父类的方法写数据,查看时就会转码,使用自己特有的方法,查看数据就会原样输出
字符打印流
PrintWriter的构造方法
PrintWriter(String fileName):使用指定的文件名创建一个新的PrintWeiter,而不需要自动执行刷新
PeintWriter(Writer out,boolean autoFlush):创建一个新的PrintWriter,out:字符输出流,autoFlush:一个布尔值,如果为真,则printIn,printf,或format方法将刷新输出缓冲区
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
public class Demo {
public static void main(String[] args) throws IOException {
//PrintStream(String fileName):使用指定文件名创建新的打印流
// PrintStream ps=new PrintStream("ps.txt");
// //写数据
// //ps.write(98);
// //使用自己的特有方法
// ps.println(99);
// ps.close();
//PrintWriter(String fileName):使用指定的文件名创建一个新的PrintWeiter,而不需要自动执行刷新
PrintWriter pw=new PrintWriter(new FileWriter("ps.txt"));
pw.println("hello");
/*
pw.write("hello");
pw.write("\t\n");
pw.flush();
*/
pw.println("world");
pw.close();
}
}
对象序列化流
概述:就是将对象保存到磁盘中,或者在网络中传输对象
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型,对象的数据和对象中存储的属性等信息
字节序列写到文件之后,相当于文件中持久保存一个对象的信息
反之该字节序列还可以从文件中读取出来,重构对象,对它进行反序列化
对象序列化流:OnjectOutputStream
对象反序列化:ObjectInputStream
对象序列化流:ObjectOutputStream
将java对象的原始数据类型和图形写入OutputStream,可以使用ObjectStream读取(重构)对象,可以通过使用流的文件来实现对象的持久存储,如果流是网络套用字流,则可以在另一个主机或另一个进程中重构对象
构造方法:
ObjectOutputStream(OutputStream out):创建一个写入指定的OutoutStream的ObjectOutputSream
方法:
void write Object(Object obj):将指定的对象写入ObjectOutputStream
ps:一个对象想要被序列化,该对象所属的类必须实现Seralizable接口
Serializable是一个标记接口,实现该接口,不需要重写任何方法
对象反序列化:ObjectInputStream
ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
构造方法:
ObjectInputStream(InputStream in):创建从指定的InputStream读取OnjectnputStream
反序列化对象的方法
object readObject():从ObjectInputStream读取一个数据
import java.io.Serializable;
public class jiangwan implements Serializable {
private static final long serialVersionUID =42L;//序列化ID值,防止修改文件出现问题
private String name;
//private int age;
private transient int age;//transient修饰的变量不参与序列化
public jiangwan() {
}
public jiangwan(String name,int age) {
this.name = name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "jiangwan{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.*;
public class Demo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
write();
read();
}
private static void write() throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ps.txt"));
jiangwan j=new jiangwan("张灵玉",23);
oos.writeObject(j);//.Not Serializable Exception
}
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("ps.txt"));
Object obj=ois.readObject();
jiangwan j=(jiangwan) obj;
System.out.println(j.getName()+","+j.getAge());
ois.close();
}
}
Properties
概述:
1:是一个Map体系的集合类
2:Properties可以保存到流中或者从流中加载
import java.util.Properties;
import java.util.Set;
public class Demo {
public static void main(String[] args) throws {
//创建对象
Properties prop=new Properties();
//Object setProperty(String key,String value):设置集合的键和值,都是String类型。底层调用Hashtable方法put
prop.setProperty("阳雷","张楚岚");
prop.setProperty("殷雷","张灵玉");
//String getProperty(String key):使用此属性列表中指定的键搜索属性
System.out.println(prop.getProperty("殷雷"));
//Set<String> stringPropertyNames():从该属性列表中返回一个不可修改的键值,其中键及其对应的值是字符串
Set<String> names=prop.stringPropertyNames();
for (String key:names){
//System.out.println(key);
String value=prop.getProperty(key);
System.out.println(key+","+value);
}
System.out.println(prop);
}
}
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class Demo {
public static void main(String[] args) throws IOException {
//把集合中的数据存到文件
//myStore();
//把文件中的数据加载到集合
myload();
}
private static void myload() throws IOException {
Properties prop=new Properties();
//void load(Reader reader):
FileReader fr=new FileReader("ps.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop=new Properties();
prop.setProperty("气体源流","张楚岚");
prop.setProperty("风后奇门","王也");
prop.setProperty("神机百炼","马仙洪");
//void store(Writer writer ,String comments):
FileWriter fw=new FileWriter("ps.txt");
prop.store(fw,null);
fw.close();
}
}
十六多线程
进程:正在运行的程序
1:是系统进行资源分配和调用的独立单位
2:每一个进程都有它自己的内存空间和系统资源
线程:是进程中的单个顺序控制流,是一条执行路劲
1:单线程:一个进程如果只有一条执行路径,则称为单线程程序
2:多线程:一个进程如果有多条执行路径,则称为多线程程序
多线程的实现方式
方式1:继承Thread类
1:定义一个类A继承Thread类
2:在A类中重写run()方法(run()是用来封装被线程执行的代码)
3:创建A类的对象
4:启动线程
run():封装线程执行的代码,直接调用,相当普通方法的调用
start():启动线程,然后由JVM调用此线程的run()方法
设置和获取线程名称
Thread类中设置和获取线程名称的方法
viod setName(String name):将此线程的名称更改为等于参数name
String getName():返回此线程的名称
线程调度
线程有两种调度模型
1:分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
2:抢占式调度模型:优先让优先级高的线程使用CPU,如果优先级相同那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些
java使用的是抢占式调度模型
Thread类中设置和获取线程优先级的方法
public final int getPriority():返回此线程的优先级
public final void setPriority(int newPriority):更改此线程的优先级
线程默认优先级是5,线程优先级范围1-10
线程优先级高仅仅表示线程获取CPU时间片的1几率高,但是要在次数比较多,或者多次运行才能看到你想要的结果
public class jiangwan extends Thread{
@Override
public void run() {
for (int i=0;i<100;i++){
//String getName():返回此线程的名称
System.out.println(getName()+":"+i);
}
}
}
public class Demo {
public static void main(String[] args) {
jiangwan j1=new jiangwan();
jiangwan j2=new jiangwan();
jiangwan j3=new jiangwan();
//viod setName(String name):将此线程的名称更改为等于参数name
j1.setName("飞机");
j2.setName("高铁");
j3.setName("汽车");
//void start()导致此线程开始执行;java虚拟机调用此线程的run方法
// j1.start();
// j2.start();
// j3.start();
// static Thread currentThread():返回当前正在执行的线程对象的引用
// System.out.println(Thread.currentThread().getName());
//public final int getPriority():返回此线程的优先级
System.out.println(j1.getPriority());
System.out.println(j2.getPriority());
System.out.println(j3.getPriority());
//public final void setPriority(int newPriority):更改此线程的优先级
System.out.println(Thread.MAX_PRIORITY);//最高值:10
System.out.println(Thread.MIN_PRIORITY);//最低值:1
System.out.println(Thread.NORM_PRIORITY);//当前值:5
j1.setPriority(6);
j2.setPriority(7);
j3.setPriority(8);
}
}
public class jiangwan extends Thread{
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(getName()+":"+i);
//static void sleep(long millis):使用当前正在正在执行的线程停留(暂停执行)指定毫秒
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
}
}
public class Demo {
public static void main(String[] args) {
// jiangwan j1=new jiangwan();
jiangwan j2=new jiangwan();
jiangwan j3=new jiangwan();
// j1.setName("那都通");
j2.setName("十佬");
j3.setName("全性");
//设置主线程
Thread.currentThread().setName("那都通");
//设置守护线程
//void setDaemon(boolean on):将此线程标记为守护线程,当运行的线程都是守护线程时,java虚拟机将退出
j2.setDaemon(true);
j3.setDaemon(true);
// j1.start();
//void join():等待这个线程死亡
// try {
// j1.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
j2.start();
j3.start();
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().ge++tName()+":"+i);
}
}
}
多线程的实现方式二
方式2:实现Runnable
1:定义一个类B实现Runnable接口
2:在B类中重写run()方法
3:创建B类的对象
4:创建A类对象,把B类对象作为构造方法的参数
5:启动线程
相比继承Thread类,实现Runnable接口的好处
避免了java单继承的局限性
适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码,数据有效分离,较好的体现了面向对象的设计思想
public class jiangwan implements Runnable{
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+","+i);
}
}
}
public class Demo {
public static void main(String[] args) {
jiangwan jw=new jiangwan();
//创建Thread类对象把B类对象作为构造方法的参数
//Thread (Runnable)
// Thread j1=new Thread(jw);
// Thread j2=new Thread(jw);
//Thread (Runnable target,String name)
Thread j1=new Thread("飞机");
Thread j2=new Thread("高铁");
}
}
线程同步
同步代码块
锁多条语句操作共享数据,可以使用同步代码块
格式:sychronizsd(任意对象){
多条语句操作共享数据的代码
}
synchronizsd(任意对象):相当于给代码加锁了
同步的好处和弊端
好处:解决了多线程的数据安全问题
弊端:当线程很多时因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率
public class jiangwan implements Runnable{
private int tickets=100;
private Object obj=new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if ( tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}}
}
}
public class Demo {
public static void main(String[] args) {
jiangwan jw=new jiangwan();
Thread j1=new Thread(jw,"窗口1");
Thread j2=new Thread(jw,"窗口2");
Thread j3=new Thread(jw,"窗口3");
j1.start();
j2.start();
j3.start();
}
}
同步方法
就是把synchronized关键字加到方法上
格式:
修饰synchronized返回值类型 方法名(方法参数){}
同步方法的锁对象时:this
同步静态方法就是把synchronized加到静态方法上
格式:修饰符 static synchronized返回值类型方法名(方法参数){}
同步静态方法的锁对象是:类名.class
public class jiangwan implements Runnable{
//private int tickets=100;
private static int tickets=100;
private Object obj=new Object();
private int x=0;
@Override
public void run() {
while (true){
if (x%2==0) {
// synchronized (obj) {
// synchronized (this) {
synchronized (jiangwan.class) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--;
}
}
}else{
// synchronized (obj) {
// if (tickets > 0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
// tickets--;
sellTicket();
}
}
}
private static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--;
}
}
// private synchronized void sellTicket() {
//
// if (tickets > 0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
// tickets--;
//
// }
// }
// private void sellTicket() {
// synchronized (obj) {
// if (tickets > 0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
// tickets--;
// }
// }
// }
}
public class Demo {
public static void main(String[] args) {
jiangwan jw=new jiangwan();
Thread j1=new Thread(jw,"窗口1");
Thread j2=new Thread(jw,"窗口2");
Thread j3=new Thread(jw,"窗口3");
j1.start();
j2.start();
j3.start();
}
}
线程安全的类
StringBuffer(常用)
线程安全,可变字符序列
从版本JDK5开始被StringBuilder代替,通常应该使用StringBuillder,因为它支持所有相同的操作,但它更快,因为它不执行同步
Vector
从java2平台v.1.2开始,该类改进了List接口,使其成为java Collections Framework的成员,与新的集合实现不同,Vector被同步,如果不需要线程安全的实现,建议使用ArrayList替代Vector
Hashtable
该类实现了一个哈希表,它将键映射到值,任何非null对象都可以用作键或者值
从java2平台v.1.2开始,该类进行了改进,实现了Map接口,使其成为java Collections Framework的成员与新的集合不同,Hashttable被同步,如果不需要线程安全的实现,建议使用HashMap代替Hashtable
Lock锁
Lock现实提供synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得和释放锁的方法
void lock():获得锁
void unlock():释放锁
Lock是接口不能直接实列化,这里采用他的实现类ReentrantLock来实例化
ReentranLock的构造方法
ReentranLock():创建一个ReentranLock的实例
public class Demo {
public static void main(String[] args) {
jiangwan jw=new jiangwan();
Thread j1=new Thread(jw,"窗口1");
Thread j2=new Thread(jw,"窗口2");
Thread j3=new Thread(jw,"窗口3");
j1.start();
j2.start();
j3.start();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class jiangwan implements Runnable{
private int tickets=100;
private Lock lock=new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--;
}
}finally {
lock.unlock();
}
}
}
}
生产者和消费者
生产者消费者模式是一个十分经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程的理解更加深刻所谓生产者问题,实际主要包含了两类线程
一类是生产者线程用于生产数据
一类是消费者线程用于消费数据
为了解耦生产者和 消费者的关系,通常会采用共享的数据区域,就像是一个仓库
生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为
消费者只需要从共享数据区中区获取数据,并不需要关心生产者的行为
package com.xd.uu;
//消费者类
public class Customer implements Runnable{
private Box b;
public Customer(Box b) {
this.b=b;
}
@Override
public void run() {
while (true){
b.get();
}
}
}
package com.xd.uu;
//生产者类
public class Producer implements Runnable{
private Box b;
public Producer(Box b) {
this.b=b;
}
@Override
public void run() {
for (int i=1;i<=31;i++){
b.put(i);
}
}
}
package com.xd.uu;
//奶箱类
public class Box {
//定义一个成员变量,表示第x瓶奶
private int milk;
//定义一个成员变量,表示奶箱的状态
public boolean state=false;
//提供存储牛奶和获取牛奶的操作
public synchronized void put(int milk){
if (state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有牛奶,就生产牛奶
this.milk=milk;
System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");
//生产完毕之后就修改奶箱状态
state=true;
//唤醒其他等待的线程
notifyAll();
}
public synchronized void get(){
if (!state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果有牛奶,就消费牛奶
System.out.println("用户拿到第"+this.milk+"瓶奶");
//消费完毕之后,修改奶箱状态
state=false;
//唤醒其他等待的线程
notifyAll();
}
}
package com.xd.uu;
//测试类
public class BoxDemo {
public static void main(String[] args) {
//创建奶箱对象,这是共享数据区域
Box b=new Box();
//创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
Producer p=new Producer(b);
//创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
Customer c=new Customer(b);
//创建2个线程,分别把生产者和消费者对象作为构造方法参数传递
Thread t1=new Thread(p);
Thread t2=new Thread(c);
//启动线程
t1.start();
t2.start();
}
}
十七 网络编程
计算机网络:是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,通过通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
网络编程:在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换
网络编程三要素
IP地址:
要想让网络中德计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接收数据的计算机,而IP地址就是这个标识,也是设备的标识
端口:
网络的通信,本质上是两个应用程序的通信,每台计算机都有很多应用程序,在网络通信时,如何区分这些应用程序呢?如果IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序了,也就是应用程序的标识
协议:
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时遵守一定的规则,在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式,传输速率,传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换,常见的协议有UDP协议和TCP协议
IP地址
:是网络中设备的唯一标识
IPv4:是每个连接网络在网络上的主机分配一个32bit地址,按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节,
IPv6:由于互联网的蓬勃发展,IP地址的需求量越来越大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,这样就解决了网络地址资源数量不够的问题
常用命令:
ipconfig:查看本机IP地址
Ping IP地址:检查网络是否连通
特殊IP地址:127.0.0.1:是回送地址,可以代表本机地址,一般用来检测
InetAddress的使用
为了方便对IP地址的获取和操作,Java提供一个类InetAddress供使用
InetAddress:此类表示InetAddress协议(IP)地址
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Demo {
public static void main(String[] args) throws UnknownHostException {
//public static InertAddress getByName(String host):确定主机名称的IP地址,主机名称可以是机器名称,也可以是机器名称,也可以是IP地址
InetAddress add=InetAddress.getByName("jiangwan");//必须是自己设备的名称
//public String getHosName():获取此IP地址的主机名
String name= add.getHostName();
//public String getHosAddress():返回文本显示中的IP地址字符串
String ip=add.getHostAddress();
System.out.println("主机名:"+name);
System.out.println("IP地址:"+ip);//UnknownHostException
}
}
端口
:设备上应用程序的唯一标识
端口号:用两个字节表示得整数,它的取值范围是0~65535,其中0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号,如果端口号被另一个服务或应用所占用,会导致当前程序启动失败
协议
:计算机网络中,连接和通信的规则被称为网络通信协议
UDP协议:
用户数据报协议(User Datagrem Protocol)
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当一台计算机向另外一台计算机发送数据时,发送端不回确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送反馈是否收到数据
TCP协议
传输控制协议(Transmission Control Protocol)
TCP协议是面向连接得通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错得数据传输,在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接得创建都需要经过“三次握手”
三次握手:TCP协议中,在发送数据得准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
第一次,客户端向服务器发出连接请求,等待服务器确认
第二次,服务器向客户端回送一个响应,通知客户端收到连接请求
第三次,客户端再次向服务器端发送确认信息,确认连接
十八 Lambda表达式
函数式编程思想概述:
在数学中,函数就是有输入量,输出量的一套技术方案,也就是“拿数据做操作”
面向对象思想强调“必须通过对象的形式来做事情”
函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”
Lambda表达式的标准格式:
组成Lambda表达式的三要素:形式参数,箭头,代码块
格式:(形式参数)->{代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法,代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
public class Demo {
public static void main(String[] args) {
new Thread(()->{
System.out.println("启动");
}).start();
}
}
Lambda表达式的使用前提
1:有一个接口
2:接口中有且仅有一个抽象方法
练习1
public interface inne {
void eat();
}
public class HelloWorLd implements inne{
@Override
public void eat() {
System.out.println("金光咒");
}
}
public class Demo {
public static void main(String[] args) {
//在主方法中调用useEatable方法
inne e=new HelloWorLd();
useEatable(e);
//匿名内部类
useEatable(new inne() {
@Override
public void eat() {
System.out.println("金光咒");
}
});
//Lambda表达式
useEatable(()->{
System.out.println("金光咒");
});
}
private static void useEatable(inne e){
e.eat();
}
}
练习2
public interface inne {
int eat(int x, int y);
}
public class Demo {
public static void main(String[] args) {
useAddble((int x,int y)->{
return x+y;
});
}
private static void useAddble(inne a){
int sun=a.eat(10,19);
System.out.println(sun);
}
}
Lambda表达式的省略模式
public interface Flyable {
void fiy(String s);
}
public interface inne {
int add(int x,int y);
}
public class Demo {
public static void main(String[] args) {
// useinne((int x,int y)->{
// return x+y;
// });
//参数的类型可以省略,多个参数不能只省略一个
// useinne((x, y)->{
// return x+y;
// });
// useFlyable((String s)->{
// System.out.println(s);
// });
//如果参数有且仅有一个小括号可以省略
// useFlyable( s->{
// System.out.println(s);
// });
//如果代码块的语句只有一条,可以省略大括号和分号
useFlyable( s->System.out.println(s));
//如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略
useinne((x, y)->x+y);
}
private static void useFlyable(Flyable f){
f.fiy("穿肠毒,刮骨刀,祸根苗,雷烟炮");
}
private static void useinne(inne i){
int sun=i.add(10,19);
System.out.println(sun);
}
}
十九 接口组成更新
接口中的默认方法
定义格式:public drfault 返回值类型 方法名(参数列表){}
注意:默认方法不是抽象方法,所以不强制被重写,但是可以被重写。重写的时候去掉default关键字
public 可以省略。default不能
接口中的静态方法
定义格式:public static 返回值类型 方法名(参数列表){}
注意:静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public 可以省略static不能
接口中的私有方法
定义格式:private 返回值类型 方法名(参数列表){}
prvate static 返回值类型 方法名(参数列表){}
注意:默认方法可以调用私有的静态方法和非静态方法
静态方法只能调用私有的静态方法
二十 方法引用
方法引用符:
:: :该符号为引用运算符,而它所在的表达式被称为方法引用
推导和省略
如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导
如果使用方法引用,同样可以根据上下文进行推导
方法引用是Lambda的孪生兄弟
public interface inne {
void Printable(String s);
}
public class Demo {
public static void main(String[] args) {
// usePrintable((String s)->{
// System.out.println(s);
// });
usePrintable( s-> System.out.println(s));
//方法引用符:::
usePrintable(System.out::println);
//可推导的就是可省略的
}
private static void usePrintable(inne p){
p.Printable("掌心雷");
}
}
Lambda表达式支持的方法引用
常见的引用方式
引用类方法,引用对象的实例方法,引用类的实例方法,引用构造器
引用类方法
其实就是引用类的静态方法
格式:类名::静态方法
Integer类的方法public static int parseInt(String s)将此String转换为int类型数据
public interface inne {
int convert(String s);
}
public class Demo {
public static void main(String[] args) {
useConvert((String s)->Integer.parseInt(s));
//引用类方法
//public static int parseInt(String s)将此String转换为int类型数据
useConvert(Integer::parseInt);
//Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
}
private static void useConvert(inne i){
int unmber=i.convert("777");
System.out.println(unmber);
}
}
引用对象的实例方法
格式:对象::成员方法
String 类中的方法public String toUpperCase()将String所有转换为大写
public interface inne {
void printUpperCsse(String s);
}
public class jiangwan {
public void printUpper(String s){
String result =s.toUpperCase();
System.out.println(result);
}
}
import java.io.PrintStream;
public class Demo {
public static void main(String[] args) {
// usePrinter((String s)->{
// System.out.println(s.toUpperCase());
// });
usePrinter(s-> System.out.println(s.toUpperCase()));
//引用对象实例
jiangwan jw=new jiangwan();
usePrinter(jw::printUpper);
//Lambda表达式被对象的实例方法替代的时候,他的形式参数全部传递给该方法作为参数
}
private static void usePrinter(inne i){
i.printUpperCsse("HelloWorld");
}
}
引用类的实例方法
引用类中的成员方法
格式:类名::成员方法
String类中的方法:public String substring(int beginInex,int endIndex)
从beginIndex开始到endIndex结束,截取字符串,返回一个字串,子串的长度为endIndex-beginIndex
public interface inne {
String mySubString(String s,int x ,int v);
}
public class Demo {
public static void main(String[] args) {
// useMyString((String s,int x,int y)->{
// return s.substring(x,y);
// });
useMyString((String s,int x,int y)->s.substring(x,y));
//引用类的实例方法
useMyString(String::substring);
//lambda表达式被类的实例方法替代的时候
//第一个参数作调用者
//后面的参数全部传递给该方法作为参数
}
private static void useMyString(inne i){
String s=i.mySubString("HelloWorld",2,4);
System.out.println(s);
}
}
引用构造器
其实就是引用构造方法
格式:类名::new
public interface inne {
jiangwan build(String name,int age);
}
public class jiangwan {
private String name;
private int age;
public jiangwan() {
}
public jiangwan(String name,int age) {
this.name = name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Demo {
public static void main(String[] args) {
//useStudentBuilder((String name,int age)->{
// jiangwan j=new jiangwan(name,age);
// return j;
//});
useStudentBuilder(((name, age) -> new jiangwan(name,age)));
//使用构造器
useStudentBuilder(jiangwan::new);
}
private static void useStudentBuilder(inne i){
jiangwan j=i.build("陆瑾",99);
System.out.println(j.getName()+","+j.getAge());
}
}
二十一 函数式接口
函数式接口:有且仅有一个抽象方法的接口
Java中的汉书式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口只有确保接口中有且仅有ige抽象方法,java中Lambda才能顺利的进行推导
@Functionallnterface:放在接口定义的上方,如果接口是函数式接口,编译通过,如果不是,编译失败,@Functionallnterface是可选的,就算不写,只要保证满足函数式接口定义的条件就行。但建议加上该注解
函数式作接口为方法的参数
public class Demo {
public static void main(String[] args) {
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程启动了");
}
});
startThread(()-> System.out.println(Thread.currentThread().getName()+"线程启动了"));
}
//定义一个方法,方法参数Runnable是一个函数式接口
private static void startThread(Runnable r){
// Thread t=new Thread(r);
// t.start();
new Thread(r).start();
}
}
函数式接口作为方法的返回值
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
//构造使用场景
//定义集合,存储字符串元素
ArrayList<String> array=new ArrayList<String>();
array.add("b");
array.add("cccc");
array.add("aa");
array.add("ddd");
System.out.println("排序前:"+array);
//Collections.sort(array);
Collections.sort(array,getComparator());
System.out.println("排序后:"+array);
}
//定义一个方法Comparator<String> getComparator()方法返回值是一个函数式接口
private static Comparator<String> getComparator(){
//匿名内部类的方法式实现
// Comparator<String> com=new Comparator<String>() {
// @Override
// public int compare(String s1, String s2) {
// return s1.length()-s2.length();
// }
// };
// return com;
// return new Comparator<String>() {
// @Override
// public int compare(String s1, String s2) {
// return s1.length()-s2.length();
// }
// };
// return (String s1,String s2)->{
// return s1.length()-s2.length();
// };
return (s1,s2)->s1.length()-s2.length();
}
}
常用的函数式接口
Java8在Java.util.function包下预定义了大量的函数式接口供我们使用
1 Supplier接口
T get():获取结果
该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
Supplier<T>接口也被称为生产型接口,如果我们指定了接口的泛型式什么类型的,那么接口中的get()方法就会生产什么类型的数据供我们使用
import java.util.function.Supplier;
public class Demo {
public static void main(String[] args) {
// String s= getString(()->{
// return "陈朵";
//});
String s=getString(()->"陈朵");
System.out.println(s);
Integer i=getInteger(()->20);
System.out.println(i);
}
//定义一个方法返回一个整数数据
private static Integer getInteger(Supplier<Integer>sup){
return sup.get();
}
//定义一个方法返回一个字符串数据
private static String getString(Supplier<String>sup){
return sup.get();
}
}
2 Consumer接口
Consumer<T>:包含两个方法
void accept(T t):对给定的参数执行此操作
default Consumer<T>andThen(Consumer after):返回一个组合的Consumer依次执行此操作,然后after操作
Consumer<T>接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
import java.util.function.Consumer;
public class Demo {
public static void main(String[] args) {
//operatorString("陈朵",(String s)->{
// System.out.println(s);
//});
operatorString("陈朵",s-> System.out.println(s));
//operatorString("陈朵",System.out::println);
// operatorString("陈朵",s -> {
// System.out.println(new StringBuilder(s).reverse().toString());
// });
operatorString("陈朵",s -> System.out.println(new StringBuilder(s).toString()));
System.out.println("--------------");
operatorString("陈朵",s -> System.out.println(s),s -> System.out.println(new StringBuilder(s).reverse().toString()));
}
//定义一个方法,用不同的方式消费同一个字符串
private static void operatorString(String name,Consumer<String> con1,Consumer<String>con2){
// con1.accept(name);
// con2.accept(name);
con1.andThen(con2).accept(name);
}
//定义一个方法,,消费一个字符串数据
private static void operatorString(String name, Consumer<String> con){
con.accept(name);
}
}
3 Predicate接口
Predicate<T>:常用的四个方法
boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
default Predicate<T>negate():返回一个逻辑的否定,对应逻辑非
default Predicate <T> and(Predicate other):返回一个组合判断,对应短路与
default Predicate <T> or(Predicate other):返回一个组合判断,对应短路或
Predicate<T>接口通常用于判断参数是否满足指定的条件
import java.util.function.Predicate;
public class Demo {
public static void main(String[] args) {
//boolean b1=checkString("hello",(String s)->{
// return s.length()>8;
//}) ;
boolean b1=checkString("hello",s -> s.length()>8);
System.out.println(b1);
boolean b2=checkString("hello world",s -> s.length()>8);
System.out.println(b2);
}
private static boolean checkString(String s, Predicate<String> per){
// return per.test(s);
// return!per.test(s);
return per.negate().test(s);
}
}
import java.util.function.Predicate;
public class Demo {
public static void main(String[] args) {
boolean b1=ch("hello",s -> s.length()>8);
System.out.println(b1);
boolean b2=ch("hello world",s -> s.length()>8);
System.out.println(b2);
boolean b3=ch("helloeorld",s -> s.length()>8,s -> s.length()<15);
}
//同一个字符串给出两个不同的判断条件,最后把这两个判断结果做逻辑与运算的结果作为最终的结果
private static boolean ch(String s,Predicate<String>pre1,Predicate<String>pre2){
// boolean b1=pre1.test(s);
// boolean b2=pre2.test(s);
// boolean b=b1&&b2;
// return b;
// return pre1.and(pre2).test(s);
return pre1.or(pre2).test(s);
}
private static boolean ch(String s,Predicate<String>pre){
return pre.test(s);
}
}
4 Function接口
Function<T R>:常用的两个方法
R apply(T t):将此函数应用于给定的参数
default<V>Function andThen(Function after):返回一个组合函数,首先该将该函数应用于输出,然后aflter函数应用于结果
Function<T R>接口通常用于参数进行处理,转换(处理逻辑由Lambda表达式实现)然后返回一个新的值
import java.util.function.Function;
public class Demo {
public static void main(String[] args) {
convert("100",s -> Integer.parseInt(s));
convert(100,i->String.valueOf(i+577));
concert("100",s -> Integer.parseInt(s),i ->String.valueOf(i+456) );
}
//定义一个方法,把一个字符串转换int。在控制台输出
private static void convert(String s, Function<String ,Integer>fun){
// Integer i=fun.apply(s);
int i=fun.apply(s);
System.out.println(i);
}
//定义一个方法,把一个int类型的数据加上一个整数之后,转换为字符串在字符串在控制台输出
private static void convert(int i,Function<Integer,String>fun){
String s=fun.apply(i);
System.out.println(s);
}
//定义一个方法,把一个字符串转换int类类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出
private static void concert(String s,Function<String,Integer>fun1,Function<Integer,String>fun2){
// Integer i=fun1.apply(s);
// String ss=fun2.apply(i);
// System.out.println(ss);
String ss=fun1.andThen(fun2).apply(s);
System.out.println(ss);
}
}
二十二 Stream流
生成流:
通过数据源(集合数组等)生成流
.stream()
中间操作:
一个流后面可以跟随零个或多个中间操作,其目的主要是打开流做出某种程度的数据过滤/映射,然后返回一个新的流交给下一个操作使用
filter()
终结操作:
一个流只能有一个终结操作当这个操作执行后,流就被使用“光”了,无法再被操作,所以这必定是流的最后一个操作
forEach()
Stream流的生成方式
Collection体系的集合可以使用stream()生成流
default Stream <E>stream()
Map体系的集合间接的生成流
数组可以通过Stream接口的静态方法of(T...valuse)生成流
import java.util.*;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
//Collection体系的集合可以使用stream()生成流
List<String> list=new ArrayList<String>();
Stream<String> listStream=list.stream();
Set<String> set=new HashSet<String>();
Stream<String> setStream=set.stream();
// Map体系的集合间接的生成流
Map<String,Integer> map=new HashMap<String ,Integer>();
Stream<String> keyStream=map.keySet().stream();//键
Stream<Integer> valueStream=map.values().stream();//值
Stream<Map.Entry<String,Integer>> entryStream=map.entrySet().stream();//键值对象
//数组可以通过Stream接口的静态方法of(T...values)生成流
String[] strArray={"hello","world","java"};
Stream<String> strArrayStream=Stream.of(strArray);
Stream<String> strArrayStream2=Stream.of("hello","world","java");
Stream<Integer> intStream=Stream.of(10,20,30);
}
}
Stream流的常见的中间操作方法
1 filter
:Stream<T> filter(Predicate predicate):用于对流中的数据进行过滤
Predicate中接口中的方法 :boolead test(T t):对给定的参数进行判断,返回一个布尔值
import java.util.*;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("张楚岚");
list.add("冯宝宝");
list.add("王也");
list.add("张灵玉");
list.add("张维");
list.add("诸葛青");
//需求1:把list集合中以张字开头的元素再控制台输出
// list.stream().filter((String s)->{
// return s.startsWith("张");
// }).forEach(System.out::println);
list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
System.out.println("------------");
//需求2:把list集合中长度为3的元素再控制台输出
list.stream().filter(s -> s.length()==3).forEach(System.out::println);
System.out.println("------------");
//需求3:把list集合中以张字开头的长度为3的元素再控制台输
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length()==3).forEach(System.out::println);
}
}
2 limit&skip
Stream<T>limit(long maxSize):返回此流中的元素组成的流。截取前指定指定参数个数的数据
Stream <T>skip(long n):跳过指定参数个数的数据,返回该流的剩余元素组成的流
import java.util.*;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("张楚岚");
list.add("冯宝宝");
list.add("王也");
list.add("张灵玉");
list.add("张维");
list.add("诸葛青");
//需求1:取前3个数据再控制台输出
list.stream().limit(3).forEach(System.out::println);
System.out.println("------------");
//需求2:跳过前3个元素把剩下的元素在控制太输出
list.stream().skip(3).forEach(System.out::println);
System.out.println("------------");
//需求3:跳过2个元素,把剩下的元素中的前两个在控制台输出
list.stream().skip(2).limit(2).forEach(System.out::println);
}
}
3 concat&distinct
static <T>Stream<T>concat(Stream a,Stream b):合并a和b两个流为一个流
Stream<T>distinct():返回由该流的不同元素,(根据Objectequals(Object))组成的流
import java.util.*;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("张楚岚");
list.add("冯宝宝");
list.add("王也");
list.add("张灵玉");
list.add("张维");
list.add("诸葛青");
//需求1:取前4个数据组成一个流
Stream<String> s1= list.stream().limit(4);
//需求2:跳过2个数据组成一个流
Stream<String> s2= list.stream().limit(4);
//需求3:合并需求1需求2得到的流并把结果输出在控制台
//Stream.concat(s1,s2).forEach(System.out::println);
//需求4:合并需求1需求2得到的流并把结果输出在控制台要求字符串元素不能重复
Stream.concat(s1,s2).distinct().forEach(System.out::println);
}
}
4 sorted
Stream<T>sorted():返回由此流的元素组成的流根据自然顺序排序
Stream<T>sorted(Comparator comparator):返回该流的元素组成的流,根据提供Comparator进行排序
import java.util.*;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("zhangchulan");
list.add("fengbaobao");
list.add("wangye");
list.add("zhanglingyu");
list.add("zhnagzhiwei");
list.add("maxianhong");
//按字母顺序把数据在控制台输出
// list.stream().sorted().forEach(System.out::println);
//按字符串长度把数据在控制台输出
// list.stream().sorted((s1,s2)->s1.length()-s2.length()).forEach(System.out::println);
list.stream().sorted((s1,s2)->{
int num=s1.length()-s2.length();
int num2=num==0?s1.compareTo(s2):num;
return num2;
}).forEach(System.out::println);
}
}
5 map&ToInt
<R>Stream <R>map(function mapper):返回由给定函数应用于此流的元素的结果组成的流
Function接口中的方法 R apply(T t)
InStream map ToInt(ToIntFunction mapper):返回一个InStream其中包含将给定函数应用于此流的元素的结果
import java.util.*;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("10");
list.add("20");
list.add("30");
list.add("40");
list.add("50");
//需求:将集合中的字符串数据转换为整数之后在控制台输出
// list.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
// list.stream().map(Integer::parseInt).forEach(System.out::println);
// list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
//int sun () 返回此流中元素的总和
int result=list.stream().mapToInt(Integer::parseInt).sum();
System.out.println(result);
}
}
6 Stream流的常见终结操作方法
void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 voidaccept(T t):对给定的参数执行此操作
long count():返回此流中的元素数
import java.util.*;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("张楚岚");
list.add("冯宝宝");
list.add("王也");
list.add("张灵玉");
list.add("张维");
list.add("诸葛青");
//需求1:把集合中的元素在控制台输出
// list.stream().forEach(System.out::println);
//需求2:统计集合中有几个以张开头的元素,并把结果在控制台输出
long count=list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(count);
}
}
Stream流的收集操作
Strream流的收集方法
R collect(Collector collector)
但是这个收集方法的参数是一个Collector接口
工具类Collectors提供了具体的收集方式
public static <T>Collector toList():把元素收集到List集合中
public static <T>Collector toSet():把元素收集到Set集合中
public Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("张楚岚");
list.add("冯宝宝");
list.add("王也");
list.add("张灵玉");
list.add("张维");
list.add("诸葛青");
/*
//需求1:得到名字为3个字的流
Stream<String> listStream=list.stream().filter(s -> s.length()==3);
//需求2:把使用Stream流操作完毕的数据收集到list集合中并遍历
List<String> names=listStream.collect(Collectors.toList());
for (String name:names){
System.out.println(name);
}*/
Set<Integer>set=new HashSet<Integer>();
set.add(10);
set.add(20);
set.add(30);
set.add(40);
set.add(50);
/*
//需求3:得到年龄大于25的流
Stream<Integer> setStream=set.stream().filter(age->age>25);
//需求4:把使用stream流操作完毕的数据收集到set集合中并遍历
Set<Integer>ages=setStream.collect(Collectors.toSet());
for (Integer age:ages){
System.out.println(age);
}*/
String[] strArray={"张楚岚,20","风星潼.19","巴伦,30","马仙洪,25"};
//需求5:得到字符串中年龄数据大于19的流
Stream<String> arrayStream=Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1])>19);
//需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键年龄作值
Map<String,Integer> map= arrayStream.collect(Collectors.toMap(s -> s.split(",")[1],s -> Integer.parseInt(s.split(",")[1])));
Set<String>keySet=map.keySet();
for (String key:keySet){
Integer value=map.get(key);
System.out.println(key+","+value);
}
}
}
二十三 反射
类加载器
类加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对这三个步骤来对类进行初始化,如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时把这三个步骤统称为另外i加载或类初始化
类加载
就是指将class文件读入内存,并为之创建一个java.lang.Class对象
任何类被使用时,系统都会为之建立一个java.lang.Class对象
类的连接
验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
准备阶段:负责为类的类变量分配内存,并设置默认初始化值
解析阶段:将类的二进制数据中的符号引用替换魏直接引用
类的初始化
在该阶段,主要就是对类进行变量进行初始化
类的初始化步骤
1:假如类还未被加载和连接,则程序先加载并连接该类
2:假如该类的直接父类还未被初始化,则先初始化其直接父类
3:假如类中有初始化语句,则系统依次执行这些初始化语句
注意:咋执行第二个步骤的时候,系统对直接父类的初始化步骤也遵顼初始步骤1-3
类的初始化时机
创建类的实例
调用类的类方法
访问类或者接口的类变量,或者为该类变量赋值
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
类加载器
类加载器的作用
负责嫁给你.class文件加载到内存中,并为之生成对应的java.lang,Class对象
虽然我们不用过分关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行
JVM的类加载机制
全盘负责:就是当一个类加载器负责加载某个Class时,该类Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
父类委托:就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有父类加载器无法加载该类时才尝试从自己的路径中加载该类
缓存机制:保证所有加载过的Class都会被缓存。当程序需要使用某个Class对象时,类加载器先从缓存区搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储到缓存区
ClassLoader:是负责加载的对象
java运行时具有以下内置类加载器
Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null,并且没有父null
Platform class loader:平台类加载器可以看到所有平台类,平台类包括有平台类加载器或者器祖先定义的java SE平台API,其实现类和JDK特定的运行时类
System class loader:它也被称为应用程序类加载器,与平台类加载器不同,系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
类加载器的继承关系:Sytem的父类加载器为Platform,而Platform的加载器为Bootstrap
ClassLoader中的两个方法
static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
ClassLoader getParent():返回父类加载器进行委派
public class Demo {
public static void main(String[] args) {
//static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
ClassLoader c=ClassLoader.getSystemClassLoader();
System.out.println(c);
//ClassLoader getParent():返回父类加载器进行委派
ClassLoader c2=c.getParent();
System.out.println(c2);
ClassLoader c3=c2.getParent();
System.out.println(c3);
}
}
反射
java反射机制:是指在运行时去获取一个类的变量和方法信息,然后通过获取到的信息来创建对象,调用方法的一种机制,由于这种动态性可以极大的增强程序的灵活新性,程序不用在编译期就确定完成,在运行期仍然可以扩展
获取Class类的对象
我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象,这里我们提供三种方式获取Class类型的对象
1:使用类的class属性来获取Class该类对应的Class对象,举例:Student.class将会返回Steudent类对应的Class对象
2:调用对象的getClass(),返回该对象所属类对应的Class对象,
该方法是Object类中的方法,所有的java对象都可以调用Class对象
3:使用Class类中得静态方法forName(String className),该方法需要传入字符串,该字符串参数得值是某个类得全路径,也就是完整包名的路径
package com.xd.yy;
public class jiangwan {
//成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
//构造方法:一个私有,一个默认,两个公共
public jiangwan() {
}
private jiangwan(String name){
this.name=name;
}
jiangwan(String name,int age){
this.name=name;
this.age=age;
}
public jiangwan(String name,int age,String address) {
this.name = name;
this.age=age;
this.address=address;
}
//成员方法:一个私有,四个公共
private void function(){
System.out.println("function");
}
public void method1(){
System.out.println("methodl1");
}
public void method2(String s){
System.out.println("method2");
}
public String method3(String s, int i){
return s+","+i;
}
@Override
public String toString() {
return "com.xd.yy.jiangwan{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
package com.xd.yy;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
//:使用类的class属性来获取Class该类对应的Class对象,
Class<jiangwan> c1 = jiangwan.class;
System.out.println(c1);
Class<jiangwan> c2 = jiangwan.class;
System.out.println(c1==c2);
System.out.println("---------------");
//调用对象的getClass(),返回该对象所属类对应的Class对象
jiangwan j=new jiangwan();
Class<? extends jiangwan> c3= j.getClass();
System.out.println(c1==c3);
System.out.println("---------------");
//使用Class类中得静态方法forName(String className),
Class<?> c4=Class.forName("com.xd.yy.jiangwan");
System.out.println(c1==c4);
}
}
反射获取构造方法并使用
Class类中用于获取构造方法
Constructor<?>[]getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[]getDeclaredConstructors():返回所有构造方法对象的数组
Constryctor<T>getConstructor(Class<?>...parameterTypes):返回单个公共构造方法
Constructor<T>getDeclaredConstrctor(Class<?>...paeameterTypes):返回单个构造方法对象
Constructor类中用于创建对象的方法
T newlnstance(Object...initargs):根据指定的构造方法创建对象
package com.xd.yy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//:使用类的class属性来获取Class该类对应的Class对象,
Class<jiangwan> c = jiangwan.class;
// Constructor<?>[] cons=c.getConstructors();
Constructor<?>[] cons=c.getDeclaredConstructors();
for (Constructor con:cons){
System.out.println(con);
}
System.out.println("------------");
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
System.out.println(obj);
// jiangwan j=new jiangwan();
// System.out.println(j);
}
}
反射获取成员变量并使用
Class类中用于获取成员变量的方法
Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象
Field类中用于给成员变量赋值的方法
void set(Object obj,Object value):给obj对象的成员变量赋值为value
package com.xd.yy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c=Class.forName("com.xd.yy.jiangwan");
// Field[] fields=c.getFields();
Field[] fields=c.getDeclaredFields();
for (Field field:fields){
System.out.println(field);
}
System.out.println("-------------");
Field addressField=c.getField("address");
//获取无参构造方法创建对象
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
addressField.set(obj,"西安");//给obj的成员变量addressField赋值为西安
System.out.println(obj);
}
}
反射获取成员方法并使用
Class类中用于获取成员方法的方法
Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name,Class<?>...parameterTypes):返回单个公共成员方法对象
Method getDelaredMethod(String name ,Class<?>....parameterTypes):返回单个成员方法对象
Method类用于调用成员的方法
Object invoke(Object obj,Object...args):调用obj对象的成员方法,参数是args,返回值是Onject类型
package com.xd.yy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c=Class.forName("com.xd.yy.jiangwan");
// Method[] methods=c.getMethods();
Method[] methods=c.getDeclaredMethods();
for (Method method:methods){
System.out.println(method);
}
System.out.println("------------");
Method m=c.getMethod("method1");
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
m.invoke(obj);
}
}
二十四 模块化
java语音随着这些年的发展已经成为一门影响深远的编程语音,无数平台,系统都是采用Java语言编写,但是,伴随着发展,java语言越来越庞大,逐渐发展乘一门“臃肿”的语言,而且,无论是运行一个大型的软件系统,海事运行一个小的程序,即使程序只需要使用java正式的部分核心功能,JVM也要加载整个JRE环境为了给java“瘦身”。让java实现轻量化,java9正式推出了模块化系统,java被拆分为N个模块,并允许java程序根据需要选择程序必须的Java模块,这样可以让java以轻量化的方法来运行
模块的基本使用
步骤
1:创建模块
2:在,模块的src目录下新建一个名为modulu-info.java的描述性文件,该文件专门定义模块名,访问权限,模块依赖等信息
描述性文件中使用模块导出和模块依赖来进配置并使用
3:模块中所有未导出都是私有的,他们是不是在模块之外被访问的
在myOne这个模块下的描述性文件中配置模块导出
模块导出格式:exports 包名:
4:一个模块要访问其他的模块,必须明确指定依赖那些模块
在myTwo这个模块下的描述性文件中配置模块依赖
模块依赖格式:requires 模块名