Java学习日志

Java学习日志

说明:此文章收录个人在JavaSE学习过程中的一些基础知识,以及一些自己爱忘记的知识点。


一.概念讲解:
1. JavaSE , JavaEE和JavaME
  • JavaSE(Java Standard Edition):标准版,定位在个人计算机上的应用。这个版本是Java平台的核心,它提供了非常丰富的API来开发一般个人计算机上的应用程序,包括用户界面接口AWT及Swing,网络功能与国际化、图像处理能力以及输入输出支持等。在上世纪90年代末互联网上大放异彩的Applet也属于这个版本。Applet后来为Flash取代,Flash即将被HTML5取代。

  • JavaEE(Java Enterprise Edition):企业版,定位在服务器端的应用。

    JavaEE是JavaSE的扩展,增加了用于服务器开发的类库。如:JDBC是让程序员能直接在Java内使用的SQL的语法来访问数据库内的数据;Servlet能够延伸服务器的功能,通过请求-响应的模式来处理客户端的请求;JSP是一种可以将Java程序代码内嵌在网页内的技术;

  • JavaME(Java Micro Edition):微型版,定位在消费性电子产品的应用上

2. JDK , JRE , JVM的关系
  • JVM(Java Virtual Machine)就是一个虚拟的用于执行bytecode字节码的”虚拟计算机”
  • Java Runtime Environment (JRE) 包含:Java虚拟机、库函数、运行Java应用程序所必须的文件。
  • Java Development Kit (JDK)包含:包含JRE,以及增加编译器和调试器等用于程序开发的文件。
  • 包含关系jdk>jre>jvm
二.前期基础(环境搭建安装jdk)
  1. Windows10下:
    •设置JAVA_HOME(解压jdk的目录)
    
    •设置CLASSPATH(.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar)
    
    •在path中加入两个新的配置
    
     %JAVA_HOME%\bin
    
     %JAVA_HOME%\jre\bin
    

    详细方法点这里

    • 测试:打开dos(win+R),输入java -version)
    2.Linux (Ubantu)下:
    • 下载jdk(Linux版本):点击下载

    • 解压缩到指定目录(以jdk-8u191-linux-x64.tar.gz为例)

    • 创建目录:

    sudo mkdir /usr/lib/jvm
    
    • 解压到该目录:
     sudo tar -zxvf jdk-7u60-linux-x64.gz -C /usr/lib/jvm 
    
    • 修改环境变量:
        sudo vi ~/.bashrc
    
    • 在文件末尾追加下面内容
    #set oracle jdk environment
    export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_191  ## 这里要注意目录要换成自己解压的jdk 目录
    export JRE_HOME=${JAVA_HOME}/jre  
    export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib  
    export PATH=${JAVA_HOME}/bin:$PATH 
    
    • 使环境变量马上生效:
    source ~/.bashrc
    
    • 系统注册此jdk
    sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.8.0_191/bin/java 300
    
    • 查看java版本,看看是否安装成功:
    java -version
    
三. Java基本语法
1.Java中的名称命名规范
  • 包名:多单词组成时所有字母都小写:xxxyyyzzz

  • 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz

  • 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个 单词开始每个单词首字母大写:xxxYyyZzz

  • 常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ

2.变量的本质和分类:
  • 变量本质上就是代表一个”可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定。我们可通过变量名来访问“对应的存储空间”,从而操纵这个“存储空间”存储的值。

  • 2局部变量、成员变量、静态变量的区别

    类型声明位置从属于生命周期
    局部变量方法或语句块内部方法/语句块从声明位置开始,直到方法或语句块执行完毕,局部变量消失
    成员变量(实例变量)类内部,方法外部对象对象创建,成员变量也跟着创建。对象消失,成员变量也跟着消失;
    静态变量(类变量)类内部,static修饰类被加载,静态变量就有效;类被卸载,静态变量消失。
3.基本数据类型
  • 整数类型:byte,short , int , long;
  • java的整型常量默认为 int 型,声明long型常量须后加‘l’或‘L’
类型占用存储空间
byte1字节 //1byte(字节)=8bit(位)
short2字节
int4字节
long8字节
  • 浮点型:float(4字节), double(8字节)

  • float类型赋值时需要添加后缀F/f

  • char 型数据用来表示通常意义上“字符”(2字节)

  • boolean 类型适于逻辑运算,一般用于程序流程控制

    • boolean类型数据只允许取值true和false,无null。

    不可以0或非 0 的整数替代false和true,这点和C语言不同

  • 字符串: String类,String类属于引用类型,可用null赋值

  • 练习题:
    String str1 = 4; //判断对错:错 需要加上双引号
    String str2 = 3.5f + “”; //判断str2对错:对
    System.out.println(str2); //输出:3.5
    System.out .println(3+4+“Hello!”); //输出:7Hello!
    System.out.println(“Hello!”+3+4); //输出:Hello!34 *讲解(“”+任何内容)会将使全部变为字符串,
    System.out.println(‘a’+1+“Hello!”); //输出:98Hello!*讲解(任何内容+“”)前面的正常运算,“”后面的内容变成字符串
    System.out.println(“Hello!”+‘a’+1); //输出:Hello!a1

4.数据类型转换注意事项
  • 自动转换(小>>大):(byte,short,char)>>> int >>> long <<< float <<<double (按照大小来自动转换)

  • 强制转换(大>>小):

    int i=2;
    short a=short(i+1);(前面添加需要转换的类型)
    .....
    
5.赋值运算符+= ,-= , /= , *=

i+=2 同义为i= i+2

short s = 3; 
s=s+2;//此时自动默认为int类型,short>>int为强制类型转换,报错,需要加(short)才行;
s+=2;//然而在使用扩展赋值运算符时,变量在参与运算时会把结果自动强制转换为当前变量的类型,可以直接运算
①和②有什么区别? 
6.i++和++i相关问题理解
.....
int i=0;
int k=i++;
System.out.println(k);
System.out.println(i);
输出k=0,i=1
.....
int i=0;
int k=++i;
System.out.println(k);
System.out.println(i);
输出k=1,i=1
    //++和--分别是加1和减1的运算,++或者--符号在变量之前,先对变量进行运算然后再取变量的值;
	//如果++或者--符号在变量之后,就先取变量的值,再对变量进行运算
  • 思考例题:
int x = 1;
int y = 1;
if(x++==2 & ++y==2){ //x++现在被看为一个整体b,此时,b应该先取值,值为1;再输出x运算为2
	x =7;
}
System.out.println(x,y);
输出:22
    //**此类问题若输出i,i的值一定是运算了的,而如果输出的是整体i++或者++1,就要按情况考虑先取值还是先运算。
 
7.逻辑运算符

&—逻辑与 | —逻辑或 !—逻辑非

&& —短路与 || —短路或 ^ —逻辑异或

aba&ba|b!aa^ba&&ba||b
truetruetruetruefalsefalsetruetrue
truefalsefalsetruefalsetruefalsetrue
falsetruefalsetruetruetruefalsetrue
falsefalsefalsefalsetruefalsefalsefalse
  • 逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写成x>3 & x<6 。

  • “&”和“&&”的区别:

    单&时,左边无论真假,右边都进行运算;

    双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。

  • “|”和“||”的区别同理,||表示:当左边为真,右边不参与运算。

  • 在不需要逻辑运算两边都参与运算的时候,尽量使用&&和||

  • 异或( ^ )与或( | )的不同之处是:当左右都为true时,结果为false。

​ 理解:异或,追求的是“异”!

  • 练习
..1..
int x = 1;
int y=1;
if(x++==2 & ++y==2){
	x =7;
}
System.out.println("x="+x+",y="+y);//输出2 2

..2..
int x = 1,y = 1;
if(x++==2 && ++y==2){
	x =7;
}
System.out.println("x="+x+",y="+y);//输出2 1


8.位运算符:(相关二进制的介绍)

直接戳这里查看哔哩哔哩求知讲堂Java课程

9.三元运算符(三目运算符)

(条件表达式)? 表达式1:表达式2;

条件表达式为true,运算后的结果是表达式1;

条件表达为false,式运算后的结果是表达式2;

  • 例子:获取两个数中的较大数
.....
    int i=2,b=3;
System.out.println((i>b)? i:b);
输出:3
  • 例子:获取三个数中的较大数
....
    int a=0,b=1,c=3;
System.out.println((a>b)?((b>c)?a:c):((a<c)?c:b));
//输出:3
10.包机制(文件夹机制)
  • 语法格式:
package pkg1.pkg2.pkg3;			//路径包含关系:pkg1>pkg2>pkg3

一般利用公司域名倒置作为包名:如com.baidu.www //com文件夹包含baidu文件夹包含www文件夹

  • 导入其他包
import package1[.package2...].(classname);
11.用户交互Scanner的使用
import java.util.Scanner	//导用scanner包
 public class Demo01{
	public static void main(String[] args){
Scanner a=new Scanner(System.in);

//输出字符时:
String str = a.next();
System.out.println(str);
//此时窗口输入字符,就会输出字符。*但是遇到空格,空格后的字符将不再输出。next()不能得到带有空格的字符串。要用nexLine.
String str1=a.nextline();
System.out.println(str1);	//nextline()以enter作为结束符,可以获得空格。

//输出数据时(int,float等类型):
int i = a.next.Int;
float f=a.next.float;
	}
}

四.控制语句
1.选择结构
  • if-else语句
if语句三种格式:

1.  if(true){
	执行代码块;
     }

2.  if(条件表达式){
	执行代码块;
      }
     else{
	执行代码块;
      }

3.  if(条件表达式){
	执行代码块;
      }
      else if (条件表达式){
	执行代码块;
      }
       ……
       else{
	执行代码块;
       }
  • switch语句
1.switch(变量){
        case 常量1:
             语句1breakcase 常量2:
            语句2break;  
        .....
        default:  //相当于else,注意冒号
           语句;
           break;
}
  • switch(表达式)中表达式的返回值必须是下述几种类型之一:byte,short,char,int,枚举,String;

  • case子句中的值必须是常量,且所有case子句中的值应是不同的;

  • default子句是可任选的,当没有匹配的case时,执行default

  • break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾

  • 例子

//使用switch语句改写下列if语句:
 	 int a = 3;
 	 int x = 100;
 	 if(a==1)
		x+=5;
 	 else if(a==2)
		x+=10;
 	 else if(a==3)
		x+=16;
 	 else		
		x+=34;

//解答:
int a=3;
int x=100;
switch(a){
  case 1:
  x+=5;
  break;
    case 2:
    x+=10;  
   break;
    case 3:
   x+=16;  
    break;
    default:  
   x+=34;
     break;
}

2.循环结构
  • while与do-while

区别:while 是先判断,后循环(使用较多),do-while是先循环后判断。

  1. while循环: 2.do-while循环
    while(布尔值){ do{
    循环体表达式; 循环体;
    } }while(布尔表达式);
     - 例:输出1-100之间所有整数和:
    public class text1{
        public stutic void main(String[] args){
            int i=1;
            int sum=0;
            while(i<=100){
                sum=i+sum;
                i++;
            }
                System.out.println(sum);
        }
    }
    //5050
  • for 循环(使用最多)
    -for(初始化变量值;布尔表达式;迭代因子){ //迭代因子控制变量增减
    循环体;
    }

    仔细理解图!false时直接退出循环。

在这里插入图片描述

-1.1-100之间的整数和:
    .....
    int sum=0;
    for(int i=1;1<=100;i++){    //注意使用分号;
		sum=sum+i;
    }
		System.out.println(sum);
//5050

-2.循环输出9-1之间的数
    ...
    for(int i=9;i>0;i--){
      System.out.print(i+"、");
       }
-----------------------------------------------------------2 .打印1-100之间所有是7的倍数的整数的个数及总和 :
System.out.print("七的倍数有:");
		int sum= 0;
		int t=0;
	for (int i=1;i<=100;i++){
		if (i%7==0){
		System.out.print(i+" ");
		sum=i+sum;
		t++;
			}
		}
	System.out.println();
	System.out.println("他们的和为:"+sum);
	System.out.println("一共有:"+t+"个");
  • 无限循环

    public class Test12 {
      public static void main(String[] args) { 
        for ( ; ; ) {  // 无限循环: 相当于 while(true)
          System.out.println("无限循环");
        }
      }
    }
    
  • 嵌套循环

-输出类似: 1 1 1 
    	  2 2 2 
    	  3 3 3 
 --代码--
   for (int i=1; i <=3; i++) {
      for(int j=1; j<=3; j++){   //当J=1,满足j<=3,输出i=1;循环j=2满足,继续输出										i=1,....,当j=4,不满足,退出;此时i进行第二次循									  环,i=2,继续上一步操作,j从再一次循环。
        System.out.print(i+"  ");
       }
      System.out.println(); //每执行大循环时空格一次。
           
===============================================================================    ---打印9*9乘法表-
    for (int i=1;i<=9;i++){
		for (int j=1;j<=i;j++){	  //如果j不小于i则会重复输出(如出现8*9=72,9*8=72)
			System.out.print(i+"*"+j+"="+(i*j)+"\t");
			}		
			System.out.println();
		}
  
3.数组的相关概念
  1. 一维数组
//声明:
数据类型+[]+变量 或者 数据类型+变量+[]	例如:int [] i;int i[];

//初始化:
--动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行
    int [] i=new int [3];	//初始化一个长度为3的数组i;
    i[0]=1;			//手动赋值第一个数为1,第二个为4,第三个为5.
	i[1]=4;
	i[2]=5;
System.out.println(i[0]+i[1]+i[2]);  //10

---静态初始化:在定义数组的同时就为数组元素分配空间并赋值。
     int [] ii=new int []{2,3,4};
	System.out.println(i[0]+i[1]+i[2]); //9
//数组中每个元素的位置从左到右是0,1,2,3.....上面i[0]=2,i[1]=3,i[2]=4.
  • 数组元素的引用:

– 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;

– 数组元素的引用方式:数组名[数组元素下标]

–数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 —>n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]

  • 每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长度(元素个数)

    int [] i=new int []{3,4,5,6};
    System.out.println(i.length);  //4
    
    • 数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被隐式初始化。例如:
    int a[]= new int[5]; 
    
    System.out.println(a[3]); //a[3]的默认值为0,此时没有赋值,要手动赋值即可
    
  1. 二维数组:

表示一维数组中的每一个元素内都包含一个数组

理解为矩阵,([x] [y]要),表示行,y表示列。注意他们的行和列的位置(下标)是从0开始的。

格式一(动态初始化):

int [][]arr=new int [3][4]

定义了名称为arr的二维数组, 二维数组中有3个一维数组,每一个一维数组中有2个元素。

给第一个一维数组1脚标位赋值为7写法是:arr[0] [1] = 7;

格式二(动态初始化)

int [][]arr=new int[3][]

二维数组中有3个一维数组。 每个一维数组都是默认初始化值null (注意:区别于格式1)

可以对这个三个一维数组分别进行初始化arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];

int [] []arr = new int [] [3] //非法

格式三:(静态初始化)

int [][] arr=new int [][]{
    {3,2,4},   //第一个一维数组arr[0]={3,2,4};
    {4,4,6},	//第二个一维数组arr[1]={4,4,6};
    {6,6,8,8}	//第三个一维数组arr[2]={6,6,8,8}
};
//第三个一维数组的长度表示方法为:arr[2].length;
如果我要输出元素3:System.out.println(arr[0][0]);


-----------------------------------------------------------------------------------------
**练习**for循环获取二维数组arr(上面的例子)中的所有元素的和。
    int sum=0;
for (int i=0;i<arr.length;i++){	//此处不能i<=arr.length,因为i从0开始,并且arr								   				  长度只有3,如果i=3,长度为4,无法满足。
    for(int j=0;j<arr[i].length;j++){	//相当于要遍历所有元素一遍然后把他们加															起来。
        sum=sum+arr[i][j];
    }
}
    System.out.println("和为:"+sum);


===================================分割线============================
*定义一个数组:
  int [] arr=new int[]{9,3,6,1,8};

******求数组中的最大最小值******
	for(int i=0;i<arr.length;i++){
        if(max<arr[i]){		//求最小值反过来即可
            max =arr[i]//与其比较,然后将其最大值存放在max里。
        }    
    }
     System.out.println("max="+max);  //max=9

********数组的复制(不是赋值)**********
int [] copy =new int [arr.length];  //copy要与原arr长度相同
for (int i=1;i<arr.length;i++){		//for循环起到遍历的作用
        copy[j]=arr[i];				//arr每一个元素复制给copy
    }   
}

*************数组的反转***************
 
4.数组的相关算法
  • 冒泡排序
请使用冒泡排序算法编写程序实现数组{25,24,12,76,101,96,28}的排序;
    int []arr =new int[] {25,24,12,76,101,96,28};
for (int i=0;i<arr.length;i++){
    System.out.print(arr[i]+" ");	//首先输出一遍原数组;
}
System.out.println();				//空格
for (int i=1;i<arr.length;i++){		//此循环代表总的需要对比的轮数,这里是6次,即要对比n-1次
    for(int j=0 ; j<arr.length - i; j++){		//此循环代表每个元素需要对比的次数,从第一个数开始依次为6,5,4,3,2,1
        if (arr[j]>arr[j+1]){					//即当i=1时,第一轮开始,25在这一轮要和六个数对比。
            int temp=0;		//输入一个数用来储存arr[j+1]的值
                temp=arr[j+1];
            arr[j+1]=arr[j];	//交换位置
          arr[j]=temp;
        }																
    }
}
    for (int i=0;i<arr.length;i++){			//输出排序后的数组
    System.out.print(arr[i]+" ");
    }
    ==若想输出反序(大到小)if处改为if(arr[j]<arr[j+1])即可==
五.面向对象编程
1.面向对象(OOP)与面向过程(POP):
  • 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为。面向对象,将功能封装进对象,强调具备了功能的对象。

  • 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。

  • **面像对象的三大特性:**封装(Encapsulation),继承(Inheritance),多态(Polymonrphism)。

  • 面向对象的思想概述:

    • 可以理解为:类=汽车设计图;对象=实实在在的汽车;
    • 面向对象设计重点是类的设计
    • 定义类其实是定义类中的变量(成员变量和成员方法)
2.Java的类及其成员:
  • 属性(Field):对应类中的成员变量;
  • 方法(Method):对应类中的方法(函数);

在这里插入图片描述

3.类的定义:
  1. 类的定义格式

修饰符(public>protected>default>private)+ class +类名(自定义的名字,驼峰命名法){

​ //类,包括成员变量和方法;

​ }

public class Persion{
    
}
  1. 声明(定义)成员变量:

    修饰符 + 数据类型 +变量名[=值] //说明:成员变量在类里面,不用赋值也可使用(int默认是0,String是null,long是0l等)

public class Persion{
    public int age=18;
    String name;
}

  1. 声明(定义)成员方法

修饰符 +返回值类型 +方法名+(参数类型 +参数名1,参数类型 +参数名2… ){

//方法体

return 返回值; //当方法的返回值为void时return及其返回值可以省略;

}

public void showName(){				
    System.out.println(name);
}
//或者:
public int showAge(int a){
    return a+1;  	//return后面的变量数据类型要i和前面的int一样;
}

///一个完整的类:
public class Persion{
     public int age=18;
    String name;
    public void showName(){		//方法创建		
    System.out.println(name);
	}
}
4.对象的创建和使用:
  1. ​ 实例化类(创建对象):类名 + 对象名称(可以新建自定义)=new +类名();
  2. ​ 方法调用:对象名称.方法名+();
  3. 成员变量调用(或者说是赋值):对象名称.成员变量名 = 。。。;
//新建一个Test类,实例化上面那个Persion类
public class Test{
    public static void main(String[] args){
        Persion per=new Persion();
        per.name="woshinidaye";  //给成员变量赋值;
        per.showAge();		//调用方法;
		System.out.println(name);
    }
}//输出:18 	woshinidaye
*************************分割线**************************************
    //也可以直接在Persion类中这样写
    public class Persion{
     public int age=18;
     public String name;
    public void showName(){		//方法创建		
    System.out.println(name);
	}
   public static void main(String[] args){
        Persion per=new Persion();
        per.name="woshinidaye";  //给成员变量赋值;
        per.showAge();		//调用方法;
		System.out.println(name);
    }    
}
    

4.面向对象思想的”落地“法则

  • 关注于类的设计,即设计类的成员:属性,方法;
  • 类的实例化,即创建类的对象(如:Presion p=new Persion());
  • 通过“对象.属性” ,“对象.方法”执行;

5.匿名对象

  • 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。 我们经常将匿名对象作为实参传递给一个方法调用。
new Persion().showAge
new Persion().name="woshinidaye"
    //像这种直接使用的就叫做匿名对象
5.方法重载
  1. 概念:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

  2. 特点:与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。调用时,根据方法参数列表不同来区别。

  //返回两个整数的和
int add(int x,int y){return x+y;}
//返回三个整数的和
int add(int x,int y,int z){return x+y+z;}
//返回两个小数的和
double add(double x,double y){return x+y;}

///判断:void show(int a,char b,double c){}构成重载的有:
void show(int x,char y,double z){}   //no
int show(int a,double c,char b){}   //yes顺序不同也是重载
c)  void show(int a,double c,char b){}  //yes顺序不同也是重载
d)  boolean show(int c,char b){}  //yes
e)  void show(double c){}  //yes
f)  double show(int x,char y,double z){}  //no
g)  void shows(){double c}  //no

6.可变个数的参数
/**
 * 用数组的方式来传递可变个数的参数
 * 如果没有参数,就要定义一个空数组,或者null.
 */
public class Persion1 {

    public void printInfor(String[] ass) {

        for (int i = 0; i < ass.length; i++) {
            System.out.println(ass[i]);
        }
    }
    public static void main(String[] args){
       Persion1 p1 = new Persion1();
        String[] as = new String[]{"张三", "11"};
        p1.printInfor(as);  //形参里面要求是数组,所以要给他定义数组才能使用
        String[] as1 = new String[]{"福建省xxx", "134324222"};
        p1.printInfor(as1);
    }
}
*************************分割线***********************************
   
    /**、
     *使用Java特有的...的方式来传递可变个数的参数,这种参数在使用时与数组的使用方式相同
     * 如果没有参数就可以不填
     * 这种...代表可以传递0到多个数组
     * 如果一个方法有多个形参,可变的形参(...这种的参数)一定要放在所有的参数最后
     * public void printInfor1(int d,String s,String...pp)这样是对的
     * public void printInfor1(int d,String...pp,String s)这样就错了
     * @param
     */
    public class Persion1 {
    public void printInfor1(String...ars) {    //这里的String还可以是int,double,等等基本类型都	是可以使用的。ars只是一个参数名字可以任意换
        for (int i = 0; i < ars.length; i++) {
            System.out.print(ars[i]);
        }
    }
    public static void main(String[] args) {
        Persion1 p1 = new Persion1();
        p1.printInfor1("张三 ","23岁 ","北京市xxxx");	//直接写想要的内容

    }
}


8.构造器详解:使用new关键字本质是在调用构造器
  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认初始化及对类中构造器的使用。

  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。

  • 特点:1.必须和类的名字相同;2.必须没有返回值,也没有void。3.默认构造器与类的修饰符一样。

public class Persion{
    public Prsion(){	//一个类什么都不写,也会存在一个方法,系统会默认自动创建(不显示),这就是构造器。	
        
    }
}
  • 作用:给成员变量初始化值或者给变量直接赋值(如:String=null,int=0等等)
********************初始化成员变量为默认值(无参)*************************
public class Persion{
    String name;
    public Prsion(){ //默认是不用写出来的,但是在传有参构造器时需要手动写。
    }
    public static void main(String[]  args){
       Persion per=new Persion;
        System.out.println(per.name);
           //输出:null
    }
 }
*****************给变量赋值(无参)**************
    public class Persion{
    String name;
    public Prsion(){ //无参构造直接给变量赋值
        name="woshinidaye";
    }
    public static void main(String[]  args){
       Persion per=new Persion;
        System.out.println(per.name);
           //输出:woshinidaye
    }
 }
  • 重点:构造有参构造器时,要用无参构造器就必须新建(平时用的时候系统默认定义,不用写)
public class Persion{
    String name;
    public Prsion(){ //如果要使用无参构造器的话此时必须写,不使用可不写
    }
    public Persion(String name){	//有参构造器
        this.name=name;  	//左边的name是成员变量上定义的,右边这个代表是形参里面的
    }
    public static void main(String[]  args){
        Persion per=new Persion("woshinidaye");	//此时会根据方法重载来显示指定输出内容
        // Persion per=new Persion();在有参构造器存在的情况下,要使用无参构造器前面就必须构造无参的
        System.out.println(per.name);
           //输出woshinidaye
    }
 }
  • 快捷键:alt+insert
    • 选择constructor+ok生成有参构造器
    • 选择constructor+select none生成无参构造器。
9.创建对象内存分析:
/**
 * 建立一个Pet类
 */
public class Pet {
    String name;
    int age;
    public void shout(){
        System.out.println("叫了一声");
    }
}
***************************************************************
/**
 * 建立Application来实例化兑对象
 */
public class Application {
    public static void main(String[] args) {
        Pet dog=new Pet();
        dog.name="旺财";
        dog.age=3;
        dog.shout();
        System.out.println(dog.age);
        System.out.println(dog.name);
        Pet cat=new Pet();
    }

}
  • 结合以上代码理解:
    在这里插入图片描述
10.四种访问修饰符的区别:

在这里插入图片描述

11.类的封装
  • 通常,应禁止直接访问一个对象中数据的实际表示,而通过操作接口来访问,称为信息隐藏。

  • 要点:属性私有(private)只能在本类内部使用,get/set,大部分情况下是对属性(成员变量)使用。

  • 通俗来说就是私有成员变量后,要在对象(类)中设立get/set公共(public)方法,可以在get/set方法中定义一些语句达到限制效果。然后在另一个类(有main方法的类)中直接可以调用get/set方法达到调用成员变量的效果。

    • 快捷键alt+insert选择getter and setter
public class Demo04 {
    //类  private:私
        //属性私有
      private  String name;
      private int id;
      private char sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;     //左边的name是成员变量里面的,右边的name是形参里面的
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

}
//实例化对象:
public class Application {
    public static void main(String[] args) {
 	  Demo04 d1=new Demo04();
        d1.setId(12311);
        System.out.println(d1.getId());
        d1.setName("woshinidaye");
        System.out.println(d1.getName());
        d1.setSex('男');
        System.out.println(d1.getSex());

    }
}   
***************************************
  //举例:对年龄进行限制
    public class Persion{
        private int age;
    public int getAge(){
        return  age;
    }
    public void setAge(int i){
        if (i>100 ||i<0){
            System.out.println("错误信息。请重新输入");
        }else{
            this.age=i;
        }
    }
}
//实例化对象:
public class Application {
    public static void main(String[] args) {
              Persion per1=new Persion();
        per1.setAge(-1);
        System.out.println(per1.getAge());
    }
}
//输出错误信息。请重新输入
  • 当形参与成员变量重名时,用this表示该类的成员变量,在任意方法内,要使用当前成员变量或成员方法,可以在前面添加this。
  • this 也可以调用构造器。
public class Person7 {
	public Person7(){
		//this("woshinidaye");//这样是错误的,因为persion7(String name)中已经有persion()了
	}
	
	public Person7(int age){
		this.age = age;
	}
	
	public Person7(String name){
		this();//等同于调用public Person7()
		this.name = name;
	}
	
	public Person7(int age, String name){
		this(1);//等同于调用public Person7(int age)
		this.age = age;
		this.name = name;
	}
	int age;
	String name;
	
	public void setName(String name){
		this.name = name;
	}
	
	public void setName1(String name){
		this.setName(name);
	}
	
	public void showInfo(){
		System.out.println("姓名:" + this.name);
		System.out.println("年龄:" + this.age);
	}
	
}
12.类的继承
  • 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

  • 此处的多个类称为子类,单独的这个类称为父类(基类或超类)。可以理解为:“子类 is a 父类”

  • 语法:public class 子类(Subclass) extends父类(Superclass){}

  • 在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和方法。

  • 子类继承了父类,就继承了父类的方法和属性。

  • 在Java 中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的“扩展”。

  • 子类不能直接访问父类的私有变量,可以通过setter/getter获取。

  • 每一个子类只能有一个唯一的父类,子类也可以可以有自己的子类,属于单继承。

  • java中默认每个类都直接或者间接继承object类。

  • Object类是所有Java类的根父类,如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类

//Persion 人:父类/基类
//Java中所有类都直接或者间接继承object类
//Java中只有单继承,没有多继承:一个儿子没有多个爹,一个爹可以有多个儿子。
public class Persion {
    //private私有的。一般思想:属性(成员变量)私有化,方法共有化。
    private int money=100;
    int age;
    String name;
    public void say(){
        System.out.println("别说话");
        }
    }

=====================================
  //学生 is 人:子类/派生类;
//子类继承父类就会拥有父类全部方法,并且也可以拥有新方法
public class Student extends Persion{
    public static void main(String[] args) {
        Student stu = new Student();
        stu.name="woshinidaye";
        stu.age=18;
        stu.say();
       // stu.money();//无法调用,要使用get/set方法调用

    }

}

  • 方法的重写(override)

定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。

要求

    • 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型。
    • 重写方法不能使用比被重写方法更严格的访问权限。
    • 重写和被重写的方法须同时为static的,或同时为非static的
    • 子类方法抛出的异常不能大于父类被重写方法的异常
    • 快捷键:alt+insert 选择override
  • 继承时修饰符的使用区别:

在这里插入图片描述

  • super关键字:在java中使用super来调用父类中的指定操作
  1. super可用于访问父类中定义的属性

  2. super可用于调用父类中定义的方法;

  3. super可用于在子类构造器方法中调用父类的构造器

  4. 格式:super.成员变量;或者super.成员方法();

注意:

  1. 尤其当父类中出现同名成员时,可以用super进行区分
  2. super的追溯不仅限于直接父类(子类可以直接用super调用父类的父类中的方法和变量)
  3. super和this很像,this代表本类对象的引用,super代表父类内存空间的标识。
  4. super只能出现在子类的方法或者构造方法中
  • super调用父类构造器

    **意义:**指定调用父类的哪个构造器,如果没有指定,则默认调用无参构造器。

    格式:super([参数1,参数2…]);

    1. 子类中所有的构造器默认都会访问父类的空参数构造器
    //定义AAnimal父类
    public class Animal{
        public Animal(){	//定义无参构造器
            System.out.println("叫了一声")}
    }
    
    //定义Dog类继承Animal类
    public class Dog extends Animal{
        public static void main(String[] args){
            Dog d=new Dog(); //在调用Dog类的默认无参构造方法,在这个过程中就使用父类的无参构造
        }
    }
    //直接运行会发现输出了:叫了一声
    //其实new Dog相当于在main方法前面前面运行了下面的代码,是默认执行的:
    public Dog (){
        super();
    }
    
  1. 当父类中没有空参数构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器,且必须放在构造器第一行。
public class Animal{
    public Animal(String name){	//定义了有参构造器。
        System.out.println("我是一直"+name);
    }
     String name;
    int age;
}

//定义Dog类继承Animal类
public class Dog extends Animal{
    //在父类只有有参构可以使用的时候,子类必须显示的构建一个构造器来调用父类的有参构造器,并且调用父类的方法(super([参数1,参数2]))要写在第一行。
    public Dog(){ 
 //如果在这里加 int i=1;  报错,因为super(..);要写在首行。
        super("沙皮狗");	//调用父类有参构造器;
    }
    public static void main(String[] args){
        Dog d=new Dog(); 
    }
}//输出:我是一只沙皮狗

3.如果子类构造器中既未显示用父类或本类的构造器,且父类中又没有无参构造器,则编译报错。

(理解:如果父类中只有有参构造,子类中无参构造器,报错,如果父类中有有参构造器和无参构造器,子类中无构造器,不报错,因为子类会默认访问父类的无参构造器,无论父类中是哪种情况,都可以通过super([参数…])来调用)。super关键字是用来指定调用无参还是有参构造器的,要使用无参就super();有参就super([参数])

public class Animal {
    String name;
    int age;
     public Animal(int age,String name){ //有参构造
     System.out.println(age);
     System.out.println(name);
    }
       System.out.println("叫了一声");
    }
}

//定义子类:
public class Dog extends Animal{
        public void printIfo(){
        super.name="wohi";
    }
    public static void main(String[] args) {
        Dog d=new Dog();
    }
}
//编译错误。虽然super()是默认执行无参构造,但在父类有参的情况下,在子类中要用无参(即子类中无构造器),父类就必须添加一个无参构造。
//如果想子类想使用父类的有参构造器,则可以通过显示的构造一个无参构造器,然后通过super([参数])来调用。

**********************看下面代码理解************************************
//父类
public class Animal {
    String name;
    int age;
    public Animal(){  //建立空构造器
    }
    public Animal(int age,String name){  //建立有参构造器
        System.out.println(age);
        System.out.println(name);
    }
    public void shout(){
        System.out.println("叫了一声");
    }
}

//子类
public class Dog extends Animal{
    public Dog(){ 	//用super()调用父类的空构造器
        super();
    }
    public Dog(int a,String n){ //建立有参构造器,并用super(...)调用父类的有参构造器					 
        super(a,n);				//这里相当于把a和n当作参数传递到父类的构造器中
    }
    public void printIfo(){
        super.name="wohi";

    }
    public static void main(String[] args) {

        Dog d=new Dog(1,"金毛");//这里传递a=1,n="金毛"
      //如果用 Dog d=new Dog();则用的就是 空构造器了 
    }
}//输出:1,金毛

13.类的特性——多态
  • 概念:
    • 1.同一方法可以根据发送对象的不同而采取多种不同的行为方式,
    • 2.一个对象的实际类型是确定的,但是可以指定的引用类型有很多 (new student()确定,但是前面的引用类型有很多可以用Persion s1=,Object s2= …)
  • 多态注意事项:
    • 1.多态是方法的多态,属性没有多态;
    • 2.父类和子类,有联系 类型转换异常, ClassCastException!
    • 3.存在条件:继承关系,方法需要重写,父类引用指 向子类对象! father f1 = new son();
      *一个引用类型变量如果声明为父类的类型,但实际引用的是子类的对象,那么该变量就不能使用子类中添加的属性和方法,需要强制类型转换才行,即:即:((子类)变量名)=[赋值],((子类)变量名).子类方法 。
  • 具体解释如下:
/**
*创建Persion父类
*/
public class Persion {
    public void print(){
        System.out.println("i am a teacher");
    }
    public void showName(){
        System.out.println("my name is 张三");
    }
}
/**
*创建Student子类继承父类
*/
public class Student extends Persion{
    int age;
    @Override	//重写父类的方法
    public void print() {
        System.out.println("i am a student");
    }
    public void eat(){
        System.out.println("food");
    }
}

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        //Studen能调用的方法都是继承父类的或者自己的
        //Persion 父类,可以指向子类但不能使用子类独有的方法如这里子类的ea()方法
        //如果要使用子类的独有方法,要通过强制类型转换; 如:((Student)s2).eat();
        //对象能执行哪些方法,和左边有关,和右边关系不大
        //当子类和父类中拥有同名方法(这里子类重写父类的方法print),程序会默认调用子类的方法。
        Student s1=new Student();
        Persion s2=new Student();
        s1.print();//i am a student
        //当子类和父类中拥有同名方法(这里子类重写父类的方法print),程序会默认调用子类的方法。
        s2.print();//i am a student
      //  s2.eat();//报错,父类无法直接调用子类的方法(高转低类型),要通过强制类型转换((Student)s2).eat();
        //对象能执行哪些方法,和左边有关,和右边关系不大
        s2.showName();//my name is 张三
        //studen能调用的方法都是继承父类的或者自己的(类型:低转高)
        s1.showName();//my name is 张三
        //s2.age=2;//报错,你的声明类型是父类的(高转低类型),现在不能使用子类的属性(成员变量),要强制类型转换((Student)s2).age=2;
    }
}


  • instanceof操作符:

    • 用于判断x是否是类A的对象,返回值为boolean类型。(这里的x表示声明后的对象名称,不能是类。)

    • 要求x所属的类与类A必须存在父子类的关系,否则编译错误。

    • 如果x属于类A的子类B,x instanceof A值也为true。

        //Object>Persion>Teacher=Student
        Object s1=new Persion();
        Persion s2=new Student();
        Persion s3=new Persion();
        Student s4=new Student();
        Teacher s5=new Teacher();
		Object s0=new Object();

        System.out.println(s1 instanceof Persion);//true
        System.out.println(s2 instanceof Persion);//true
        System.out.println(s3 instanceof Persion);//true
        System.out.println(s4 instanceof Persion);//true
        System.out.println(s4 instanceof Student);//ture
        System.out.println(s1 instanceof Student);//false
		System.out.println(s0 instanceof Persion);//false
        //System.out.println(s5 instanceof Student);//编译报错,同级直接无法使用
  • Object类详解:
  1. Object类是所有Java类的根父类

  2. 如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类 。

//理解object作为根父类的作用:
//现在上题中已经建立persion父类,student子类,teacher子类
public class Test {
    public void text01(Object obj){ //给test01方法传递一个不知道名字的类
        public static void main(String[] args) { 	
        Test t1=new Test();
        Persion t2=new Persion();
        Student t3=new Student();
        t1.text01(t2);//相当于:Object t2=new Persion();
        t1.text01(t3);
        t1.text01(new Teacher());//与上面一样的操作
    }
}
  1. public boolean equals(Object obj):判断某个对象于此对象是否相等
//理解object作为根父类的作用:
//现在上题中已经建立persion父类,student子类,teacher子类
public class Test {
    public void text01(Object obj){ //给test01方法传递一个不知道名字的类
        public static void main(String[] args) { 	
        Test t1=new Test();
        Persion t2=new Persion();
        Student t3=new Student();
        t1.text01(t2);//相当于:Object t2=new Persion();
        t1.text01(t3);
        t1.text01(new Teacher());//与上面一样的操作
            System.out.println(t2.equals(t3));//false
         Persion t4=new Persion();    
             System.out.println(t4.equals(t2));//false,在堆内存里面重新开一个new persion他们指向的地址都不一样。
            t4=t2;
         System.out.println(t4.equals(t2));//true,此时已经直接赋值为相同地址的对象了    
    }
}
  1. int hashCode():打印当前对象的哈希码值:
  System.out.println(t2.hashCode());
  1. String toString():打印当前对象的内存地址
System.out.println(t2.toString());
System.out.println(t2);//或者直接这样也是默认调用toString方法的,效果一样。
  • 包装类:主要用处是字符串类型和基本数据类型的转换。
public class test {
    public static void main(String[] args) {
        Integer i=1;//自动装箱
        int i1=i;//自动拆箱
        System.out.println(i1);
        Boolean  b=false;//自动装箱
        boolean b1=b;//自动拆箱
        System.out.println(b1);
        //字符串类型转化为基本数据类型;
        string str1="122";
        String str2 = "30.3" ;	
         String str3 = "false" ;	
        int p=Integer.parseInt(str1);
        float f=Float.parseFloat(str2);
        boolean bo=Boolean.parseBoolean(str3);

        //基本数据类型转化为字符串类型;
        int i=222;
        float f=3.3;
        boolean bo=false;
        String str1=String.valueOf(i);
        String str2=String.valueOf(f);
        String str3=String.valueOf(bo);
    }
}
14. static关键字:
  • 用static修饰的属性(成员变量)和方法分别叫做类变量也叫静态变量和类方法;

  • 在Java类中,可用static修饰属性、方法、代码块、内部类;

  • 被修饰后的成员具备以下特点:

    • 随着类的加载而加载

    • 优先于对象存在

    • 修饰的成员,被所有对象所共享

    • 访问权限允许时,可不创建对象,直接被类调用(类名.方法 或者 类名.属性)。

public class test {
    public static int age;
    public String name ;
    public static void showName (){
        System.out.println("my name is 张三");
    }
    public static void main(String[] args) {
        test.showName();//直接可以调用方法和属性
        test.age=21;
        System.out.println(age);
    }
}

  • 注意:
    • 因为不需要实例就可以访问static方法,因此static方法内部不能有this。(也不能有super ? YES!)
    • 重载的方法需要同时为static或者非static的。
15.单例(Singleton)设计模型:
  • 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

  • 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。

    • 两种方法:饿汉式和懒汉式;
    • 区别:饿汉式是先new好对象,然后其他的人来调用以后的都是new好的对象,
      懒汉式是没new之前是null的,第一次new过之后,其他人调用的都是new好的对象。
    • 好处:程序一开始就将对象new好,其他人直接用就好,减少时间。
/**
*饿汉式
*/
public class Singlen {
   private Singlen(){  //	//1.将构造器私有化,保证在此类的外部,不能调用本类的构造器。

   }
   private static Singlen onlyone=new Singlen(); //私有的,只能在类的内部访问

   public static Singlen getSinglen(){    //getSingle()为static,不用创建对象即可访问
       return onlyone;
   }
}
//测试类:
public class Application {
   public static void main(String[] args) {
       Singlen s1=Singlen.getSinglen();//访问静态方法;达到new Singlen()的效果
       Singlen s2=Singlen.getSinglen();//s1,s2都使用的是同一个new Singlen()
       //测试:
       if (s1==s2){
           System.out.println("s1 is equals to s2!");
       }
   }
}

/**
    * 懒汉式
    */
public class Singlen {
    private Singlen() {   //1.将构造器私有化,保证在此类的外部,不能调用本类的构造器。

   }

   private static Singlen instance = null;  //2.先声明类的引用, //4.也需要配合static的方法,用static修饰此类的引用。

   public static Singlen getSinglen() {  //3.设置公共的方法来访问类的实例
       //3.1如果类的实例未创建,那些先要创建,然后返回给调用者:本类。因此,需要static 修饰。
       if(instance == null){
           instance = new Singlen();
       }
       //3.2 若有了类的实例,直接返回给调用者。
       return instance;

   }
}
//测试类:
public class Application {
   public static void main(String[] args) {
       Singlen s1=Singlen.getSinglen();//访问静态方法;达到new Singlen()的效果
       Singlen s2=Singlen.getSinglen();//s1,s2都使用的是同一个new Singlen()
       //测试:
       if (s1==s2){
           System.out.println("s1 is equals to s2!");
       }
   }
}  
  • 理解main方法:
public static void main(Sring[] args){
    
}
    • 由于java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个string类型的数组参数,该数组中保存执行java命令运行的类的参数。
16.类的成员之四:初始代码块
  • 作用:对java对象进行初始化;
  • 分为静态代码块(前面加static)和非静态代码块
  • 执行顺序:1,声明成员变量的默认值;2,显式初始化、多个初始化块依次被执行(同级别下按先后顺序执行);3,构造器再对成员进行赋值操作
    1. 非静态代码块:
public class demo01 {
    String name;
    public demo01(){
        this.name="张三";
        System.out.println("这是一个构造器");
    }
    //这就是非静态代码块
    {
        System.out.println("这是一个代码块1");
    }
    {
        System.out.println("这是一个代码块2");
    }
    {
        System.out.println("这是一个代码块3");
    }
}
//测试类:
public class Test {
    public static void main(String[] args) {
        demo01 d=new demo01();
    }
}

/*
执行顺序:
第一步:类属性的默认初始化和显示初始化;
第二步:执行代码块的内容(有多少个代码块就执行多少次);
第三步:执行构造器;
输出:
这是一个代码块1
这是一个代码块2
这是一个代码块3
这是一个构造器
 */
  1. 静态代码块:
public class demo01 {
    String name;
    static int age;
    public demo01(){
        this.name="张三";
        System.out.println("这是一个构造器");
    }
     //静态代码块:
    static {
        age=1;
       showAge();   //这里只能执行静态方法和属性
        System.out.println("====这是一个静态代码块====");
    }
    public static void showAge(){
        System.out.println(age);
    }
}
//测试类:
public class Test {
    public static void main(String[] args) {
        demo01 d=new demo01();
        demo01 d1=new demo01();

    }
}
/*
输出:
1
====这是一个静态代码块====
这是一个构造器
*/
  • 对比:
public class demo01 {
    String name;
    static int age;
    public demo01(){
        this.name="张三";
        System.out.println("这是一个构造器");
    }
    //这就是非静态代码块
    {
        System.out.println("这是一个非静态代码块1");
    }
    {
        System.out.println("这是一个非静态代码块2");
    }
    {
        System.out.println("这是一个非静态代码块3");
    }
    //静态代码块:
    static {
        age=1;
       showAge();   //这里只能执行静态方法和属性
        System.out.println("====这是一个静态代码块====");
    }
    public static void showAge(){
        System.out.println(age);
    }
}

//测试类:
public class Test {
    public static void main(String[] args) {
        demo01 d=new demo01();
        demo01 d1=new demo01();

    }
}
//在运行中,非静态代码块每次new对象都要重新执行,静态代码块只执行一次
/*
输出:
1
====这是一个静态代码块====
这是一个非静态代码块1
这是一个非静态代码块2
这是一个非静态代码块3
这是一个构造器
这是一个非静态代码块1
这是一个非静态代码块2
这是一个非静态代码块3
这是一个构造器

*/
  • 总结:

非静态代码块:没有static修饰的代码块

​ 1.可以有输出语句。

​ 2.可以对类的属性声明进行初始化操作。

​ 3.可以调用静态和非静态的变量或方法。

​ 4.若有多个非静态的代码块,那么按照从上到下的顺序依

​ 次执行。

​ 5.每次创建对象的时候,都会执行一次。且先于构造器执行

静态代码块:用static修饰的代码块

1.可以有输出语句。

2.可以对类的属性声明进行初始化操作。

3.不可以对非静态的属性初始化。即:不可以调用非静态的属

​ 性和方法。

4.若有多个静态的代码块,那么按照从上到下的顺序依次执行。

5.静态代码块的执行要先于非静态代码块。

6.静态代码块只执行一次。

  • **用处:**实际来发中static静态代码使用较多,用来初始化类的静态属性(static类型的属性)。
public class demo01 {
    String name;
    static int age;
    public demo01(){
        this.name="张三";
    }
public  void showInf(){
    System.out.println("你好!");
  }

}
//测试类(注意理解匿名内部类的创建和使用):
public class Test {
    public static void main(String[] args) {
        demo01 de=new demo01(){ //构建了一个匿名内部类!相当于在此构建了一个没有类名的demo01的子类;
       //没有类名就说明不能用显示的new的方式来创建对象,即没有构造器,无法初始化属性,此时就需要代码块{}来做初始化的工作、
         //问题,现在想把demo01中的name改为李四,但是不想动dem01中的代码,就要使用代码块代替构造方法。
            {
                super.name="李四";
            }
            @Override    //因为是demo01的子类,所以可以重写父类的方法
            public void showInf() {
                System.out.println("我是没名字的子类");
            }
        };
        System.out.println(de.name);
       de.showInf();
    }
}
    /*
    输出:
    李四
    我是没名字的子类
    */

  • final关键字:
public class demo {
    //final标记的变量变为常量,常量必须赋值。、
    //final+static修饰的变量为全局常量;
    //final修饰的类不能被继承;
    //final修饰的方法不能被重写;
    final String NAME="";//常量,名称大写,且只能被赋值一次,且必须赋值才行;
}

17.抽象类
/**
 * 抽象abstract:理解:一个动物的类为父类,狗类和鱼类为子类,父类里面有一个移动方法,但狗和鱼的移动方法不一样
 * 所以我只能让父类抽象化,子类具体化;
 * 用abstract关键字来修饰一个类时,这个类叫做抽象类;
 *  用abstract来修饰一个方法时,该方法叫做抽象方法。该方法只有声明,没有方法体,以分号结束。
 *  如:public abstract void move([参数类型 参数名...]);
 *  抽象类也可以继承抽象类(子类也可以作为抽象类)
 *  1.含有抽象方法的类必须被声明为抽象类。
 *  2.抽象类不能被实例化。抽象类是用来作为父类被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
 *  3.不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。
 */
public abstract class Animal {
    public abstract void move();  //只要有一个抽象方法,类就必须是抽象类
}

 class Fish extends Animal{//直接建立一个子类继承父类

     @Override          //重写animal的方法此类才能用//理解如果没有重写抽象类的所有方法,则这个类依然是抽象类
     public void move() {
         System.out.println("游");
     }
 }
 class Dog extends Animal{
     @Override
     public void move() {
         System.out.println("跑");
     }
 }
 abstract class Bird extends Animal{ //抽象类也可以继承抽象类
     @Override
     public void move() {

     }
    public abstract void shut();//只要有一个抽象方法,类就必须是抽象类
 }
class littleBirld extends Bird{
     @Override
     public void shut() {
         System.out.println("zzz");
     }
}
//测试类:
public class test {
    public static void main(String[] args) {
        Fish fish=new Fish();
        fish.move();
        Dog dog=new Dog();
        dog.move();
    }
}
/*
*游
*跑
/*
18.接口(interface)和实现(implements)
  • 接口(interface)是抽象方法和常量值的定义的集合。

  • 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。

  • 特点:

    • 用interface来定义。
    • 所有成员变量默认是public static final修饰;
    • 所有方法都默认是由public abstract 修饰;
    • 接口中没有构造器;
    • 接口采用多层继承机制;
  • 写法:

//接口test
public interface Test {
    int ID=1; //public static final int ID=1;
    void method();//public abstract void test01();
}
//接口test01
public interface Test01 {
    void method01();//public abstract void method();
}
//接口可以继承接口
public interface Test02 extends Test01 {

}
  • 实现接口

    • 子类继承父类,只能继承一个父类
      • 类可以实现多个接口,多个接口用逗号分隔(使用关键字implements)
      • 如果类没有实现接口的所有方法,则这个类就要定义成抽象类
public class Application implements Test,Test01{
    @Override
    public void method() {  //需要实现接口的所有方法,不然不能使用,要被定义为抽象类;

    }

    @Override
    public void method01() {

    }
}
  • 如果一个类既继承父类,又实现接口,那么先继承,后实现。
public  class Test04 extends Application implements Test01 ,Test{
    //一个类可以实现多个接口,接口也可以继承其它接口。
}
  • 接口的主要用途就是被实现类实现。(面向接口编程)

  • 与继承关系类似,接口与实现类之间存在多态性:

//接口test
public interface Test {
    int ID=1; //public static final int ID=1;
    void method();//public abstract void test01();
}
//实现类
public class Application implements Test,Test01{
    @Override
    public void method() {

    }
    public static void main(String[] args) { //main方法主程序入口
        Test t=new Application();//体现多态性
        t.method(); //可以发现他只能调用自己的方法
    }
}
  • 为什么要用接口呢?

在这里插入图片描述

  • 接口对比抽象类:

    • 抽象类是对一类事物的高度抽象,其中既有属性也有方法,
    • 接口是对方法的抽象,也就是对一系列动作的额=抽象。
19.类的成员之五——内部类:
  • 在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
public class Test3 { //外部类
	int i;
	public int z;
	private int k;
	
	class A{   //内部类A
		int i;
		public void setTest3Fileds(){
			Test3.this.i = 1; //调用外部类的属性
			Test3.this.z = 2;
			Test3.this.k = 3;
		}
		
		public void set(){
			this.i = 10; //调用自己的属性
		}
	}
	//如果内部类是static的,就不能使用外部类的非static的成员
	static class B{
		
	}
	
	abstract class C{
		
	}
	
	class D extends C{ //内部类可以继承
		
	}
	
	public void setInfo(){
		new A().setTest3Fileds();//外部的类要用自己的内部类的方法,得先new内部类的对象
	}
	
	public void showInfo(){
		System.out.println(this.i);
		System.out.println(this.z);
		System.out.println(this.k);
	}
	
	public static void main(String[] args) {
		Test3 t = new Test3();
		t.setInfo();
		t.showInfo();
	}
}//输出1,2,3

  • 内部类的最大作用:实现多重继承
public class Test{
    public static void main(String[] args) { //调用showIfo方法来实现调用B,C的方法;先看下面再回来看这一步
        A a=new A();
        a.showInfo();
    }
}
    class B{  //一个类B
      public void testB(){

      }
    }
    class C{  //一个类C
        public void testC(){
        }
    }
/**
 * 现在我想让A同时继承B和C,该怎么办?Java中是不能一个子类类继承多个父类的;
 * 用内部类变相实现多重继承;
 * 解决java不能多重继承的问题
 */
class A {  //类A
    public class InnerB extends B{ //在类A中创建一个内部类继承B;

        @Override
        public void testB() {  //可以重写B的方法
            System.out.println("这是重写之后的B的方法");
        }
    }
    public class InnerC extends C{//在类A中创建一个内部类继承C;

        @Override
        public void testC() { //可以重写C的方法
            System.out.println("这是重写之后的C的方法");
        }
    }
    public void showInfo(){  //在A中建立方法来调用testB和testC方法
        new InnerB().testB();  //先new才能调用testB方法,这里使用了匿名类,直接new InnerB来使用,不给他名称
        new InnerC().testC();
    }
}
//输出:这是重写之后的B的方法,这是重写之后的C的方法
20.异常处理
  1. 异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。

  2. 分类:

  • Error: JVM系统内部错误、资源耗尽等严重情况

  • Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,例如:•空指针访问•试图读取不存在的文件•网络连接中断。
    在这里插入图片描述

  • 常见异常:

    • RuntimeException

    •错误的类型转换

    •数组下标越界

    •空指针访问

    • IOExeption

    •从一个不存在的文件中读取数据

    •越过文件结尾继续读取EOFException

    •连接一个不存在的URL

3.异常处理机制:(只能处理Exception异常)

  • 未处理异常时,当程序运出错时,后面的代码就会全部终止运行,所以我们要制作异常机制来将可能会发生异常的代码集中起来,与正常代码分开

  • 抓抛模型:

    1. try…catch和finally
try{
    //可能发生异常的语句,在这里如果有异常代码,则在try{}中后面的代码将不再被执行
}catch(Exception类或者其子类e){ //()里面如果未知异常的类型,就用所有异常的父类Exception
    //对捕获的异常进行处理
}finally{  //finally关键字表示最终执行的代码,可以不用写
    
}
       
//详情:
=====================================================
 /**
 * 异常语句,程序将不执行剩下的代码。
 */
public class Test {
    public static void main(String[] args) {
        int i = 0;
        System.out.println(3/i);
        System.out.println("ok");
    }
} //Exception in thread "main" java.lang.ArithmeticException: / by zero
       
/**
 * 捕获异常语句,程序可以正常运行
 */
public class Test {
    public static void main(String[] args) {
        int i = 0;
        try{
            System.out.println(3/i);
        }catch (Exception e){
           //e. e.printStackTrace();表示获取这个异常到底是是什么类型,可以不写
           //System.out.println(e.getMessage());//getMessage表示异常信息,可以不写
        }
        System.out.println("ok");
    }
}//ok
 /**
  *finally的意义:表示最终执行的代码;
  */
      .....
        int i = 0;
        try{
           System.out.println("1");
           System.out.println(3/i); //此处异常后,下面的输出2就不执行了
           System.out.println("2");
        }catch (Exception e){
          System.out.println("3");
        }finally{
          System.out.println("4");
        }
       //输出1,3,4,
       

  1. 抛出异常——throws 关键字 (方法异常)

•如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显式地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

•在方法声明中用 throws 子句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

  • 声明抛出异常:
[修饰符] 返回值类型(或者void) 方法名 ([参数类型+ 参数名称]...throws 异常1,异常2(直接用Excpetion所有异常的父类)....{
    //方法体
}
//举例
public void readFile(String file) throws FileNotFoundException{
    ....
  // 读文件的操作可能产生FileNotFoundException类型的异常
	FileInputStream fis = new FileInputStream(file);   
    ....
}
  • 举例:
public class Test01 {
    public void  test(int i)throws Exception{ //定义一个抛出异常的有参方法
        int b=1/i;
        System.out.println(b);
    }
    public static void main(String[] args) { //也可以在main方法出继续抛出异常,但是直接抛到jvm内无法处理
        Test01 t=new Test01();
        try{            //用throws抛出异常以后在调用方法时必须用try..catch来捕捉;
            t.test(0);
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}//输出:/ by zero
  • 注意:如果一个父类中有抛出异常的方法,则子类重写父类的方法时,不能抛出比父类范围更大的异常类型
//父类A
public class A{
    public void method() throws IOException{
        ...
    }
}
//子类B1
 public class B1 extends A{
     public void method() throws FileNotFoundException{
         ....
     }
 }
public class B2 extends A{
    public void method() throws Exception{ //Erro 错误
        
    }
}
  1. 人工抛出异常(throw关键字):人工抛出自己命名的异常名称

    与throws不同,throw用在方法体内,并且抛出的是一个异常对象,并且也要通过throws关键字和try…catch来捕获处理。

//语法格式
[修饰符] 返回值类型(或者void) 方法名 ([参数类型+ 参数名称]...throws 异常1,异常2(直接用Excpetion所有异常的父类)....{
    //方法体...
    throw new Exception类或者子类构造方法;
}
//举例
public class Test02 {
    public void printAge(int age) throws Exception {
        if (age < 0) {
            //进行逻辑判断,如果年龄为负数,则抛出异常
            throw new Exception("输入年龄有误,必须是正整数");
        } else {
            System.out.println("年龄为:" + age);
        }
    }

    public static void main(String[] args) {
        Test02 t2 = new Test02();
        int age=-1;
        //定义try ..catch来捕获异常
        try {
           t2.printAge(age);
        }catch (Exception e){
            System.out.println("捕获的异常信息为:"+e.getMessage());
        }
    }
}
/**
 * 输出:捕获的异常信息为:输入年龄有误,必须是正整数
 */

4.自定义异常类:(了解)

 public class MyException extends Exception{//自定义异常类
            public MyException(String msg){ //构造器
                super(msg); //调用父类的构造方法
            }
    }
//定义一个类
public class Test02 {
    public void printAge(int age) throws MyException { //抛出自定义异常类:
        if (age < 0) {
            //进行逻辑判断,如果年龄为负数,则抛出异常
            throw new MyException("输入年龄有误,必须是正整数");
        } else {
            System.out.println("年龄为:" + age);
        }
    }
    ......
        //进行一系列try... catch捕获。
六.集合
1.概念:用于存放对象容器,存放于 java.util 包中。

•①、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。

•②、集合存放的是多个对象的引用,对象本身还是放在堆内存中。

•③、集合可以存放不同类型,不限数量的数据类型。

2.Java 集合可分为 Set、List 和 Map 三种大体系
集合Collection(单列集合的根接口)Map(双列集合根接口)
Set(接口):无序、不可重复的集合——由HashSet和TreeSet类来实现Map(接口):具有映射关系的集合——HashMap类实现
List(接口):有序,可重复的集合——由ArrayList类来实现
  • HashSet(无序、不可重复的集合)

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet.

    • 特点:不能保证元素的排列顺序,不可重复,HashSet不是线程安全, 集合元素可以使用null
    • HashSet实现了set接口,set接口继承了coolection接口。
//导入相应包
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Test {
    public static void main(String[] args) {
        Set set= new HashSet();
        set.add(1); //添加元素
        set.add("a");
        System.out.println(set); //输出:[1, a]
        set.remove("a"); //移除元素
        System.out.println(set); //输出[1]
        set.contains("a"); //判断是否存在该元素
        System.out.println(set.contains("a")); //false
        set.clear();//清空集合
        System.out.println(set);//[]
    }
}
    • set集合遍历:
public class Test {
    public static void main(String[] args) {
         Set set= new HashSet();
 /**
 * 集合遍历讲解
 */
        set.add("a");
        set.add("b");
        set.add("c");
        set.add("d");
        set.add("e");
        System.out.println(set);
        //1.使用迭代器遍历集合(推荐使用)
        Iterator it =set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //2.使用for each迭代集合(多数使用)
        for(Object obj :set){ //意思是把set的每一个值取出来赋值给obj,直到循环所有的set元素
            System.out.println(obj);
        }

       //获取集合元素个数
        System.out.println(set.size());//5
        //如果在集合中再添加一个相同元素:set集合存的值是不重复的。
        set.add("a");
        System.out.println(set);//输出后发现a并没有被添加,输出set.size()大小也没变

        //添加null元素
        set.add(null);
        System.out.println(set);//输出:[null, a, b, c, d, e],null在第一个,说明无序性
    }
}


  • 泛型
/**
* 泛型的使用,接着上面的代码
*/
		....
        set.add(1); //可知set集合可以存放各种类型的对象
        set.add(true);
        set.add("sdd");
        //现在想让集合中只能存入同样类型的对象,怎么办?
        Set<String> set1= new HashSet<String>(); //这样就只能存放字符串类型的对象
        set1.add("asx");
        //set1.add(1)报错
        Set<Integer> set2= new HashSet<Integer>(); //这样就只能存整数类型的对象
        set2.add(2);
      //Object是所有类的父类,所以Set<Object> set2=new HashSet<Object>();与不写是一样的
        //也就是Set set= new HashSet();默认是Object类型,所以可以存放任何类型
    }
}
  • TreeSet
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class Test1 {
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<Integer>();
        //自然排序:TreeSet会按大小默认排序(在同一泛型内才行)
        set.add(1);
        set.add(5);
        set.add(3);
        set.add(8);
        System.out.println(set);//输出:[1, 3, 5, 8]

        //其它使用方法与HashSet相同
        set.contains(9);//false,集合内不存在9
        //set.clear();//清除集合

        //1迭代器遍历:
        Iterator it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        // 2.使用for each迭代遍历集合
        for (Integer i:set ){
            System.out.println(i);
        }
    }
}


/**
 * TreeSet的定制排序:实现comparator接口
 * 把student对象放到TreeSet集合中并且按照年龄排序
 */
class Student implements Comparator <Student>{ //要添加泛型,Student类型
    int age;
    String name;
    public Student(){  //Student空构造器

    }
    public Student (int age,String name){ //有参构造器
        this.age=age;
        this.name=name;
    }
    @Override                            //重写compare方法。自己定制比较规则
    public int compare(Student student, Student t1) {
        if(student.age>t1.age){ //前一个大于后一个,这一套表示正序排列,
            return 1;           //如果要倒序,直接调换<>位置即可
        }else if(student.age<t1.age){
            return -1;
        }else {
            return 0;
        }
    }
}
public class Test5 {
    public static void main(String[] args) {
        Student stu1=new Student(14,"张三");
        Student stu2=new Student(16,"李四");
        Student stu3=new Student(9,"王五");
        Student stu4=new Student(19,"赵六");

        TreeSet<Student> set=new TreeSet<Student>(new Student());//new Student()的原因是为了传入comparator
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        for(Student s:set){
            System.out.println(s.age+"  "+s.name);
        }
    }
}


  • List接口的实现 ——ArrayList
    • List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
    • 允许使用重复元素,可以通过索引来访问指定位置的集合元素
    • 默认按元素的添加顺序设置元素的索引。
    • 集合里添加了一些根据索引来操作集合元素的方法
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class Test2 {
    public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        list.add("b"); //第一个,索引下标0;
        list.add("d");//第二个,索引下标1;
        list.add("c");//第3个,索引下标2;
        list.add("a");//第4个,索引下标3;
        System.out.println(list);//输出:[b, d, c, a]
        System.out.println(list.get(2));//输出:c,可以通过索引来访问指定位置的集合元素
        list.add("d");
        System.out.println(list);//[b, d, c, a, d],可重复;

        list.add(1,"f");//在指定索引下标的位置插入数据
        System.out.println(list);//[b, f, d, c, a, d]

        //新建一个集合l并添加元素
        List<String > l=new ArrayList<>();
        l.add("1123");
        l.add("3322");
        //在指定的索引下标内插入集合
        list.addAll(2,l);//在2位置插入l集合
        System.out.println(list);//输出:[b, f, 1123, 3322, d, c, a, d]

        System.out.println(list.indexOf("d"));//4,获取指定元素在集合中第一次出现的索引下标
        System.out.println(list.lastIndexOf("d"));//7,获取指定元素在集合中最后一次出现的索引下标

        list.remove(2);//()里面写指定的索引下标位置,根据下标移除元素
        System.out.println(list);//[b, f, 3322, d, c, a, d],

        list.set(1,"fff");//根据指定的索引下标修改元素
        System.out.println(list);//[b, fff, 3322, d, c, a, d]

        List <String> sub=list.subList(2,4);//根据索引下标的起始位置截取一段新的集合,元素的索引截取时,不包括最后一个元素也就是[2,4)
        System.out.println(sub);//[3322, d],包括第一个,不包括后面一个,理解为:[2,4)

        System.out.println(list.size());// 7,集合长度
    }
}

  • Map集合

    • Map 用于保存具有映射关系的数据,因此 Map 集合里保存着两组值,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value。

    • Map 中的 key 和 value 都可以是任何引用类型的数据

      Map 中的 Key 不允许重复,即同一个 Map 对象的任何两个 Key 通过 equals 方法比较中返回 false。

    • Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的,确定的 Value。

    • 实现类——HashMap类
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Test3 {
    public static void main(String[] args) {
       // Map<Object key,Object Value >
        Map<String ,Integer> map=new HashMap<String, Integer>();
        map.put("b",1);//添加数据,key不能相同,且唯一,value可以是相同的
        map.put("c",2);
        map.put("e",2);
        System.out.println(map);//{b=1, c=2, e=2}

        System.out.println(map.get("b"));//输出:1,根据key取value的值
        map.remove("c");//根据key移除键值对
        System.out.println(map);//{b=1, e=2}

        System.out.println(map.size());//map集合的长度

        System.out.println(map.containsValue(1));//true,,判断当前的集合是否包含指定的value。
        System.out.println(map.containsKey("a"));//false,判断当前的集合是否包含指定的key。

        System.out.println(map.keySet());//[b, e],获取map集合的key集合
        System.out.println(map.values());//[1, 2],获取所有value值

        //遍历map集合方法一,通过map.KeySet();
        Set<String> keys=map.keySet();//获取map所有key的集合(如上,是一个set集合)
    	//for each遍历
        for (String key :keys){
            System.out.println("key:"+key+",value:"+map.get(key));//输出:key:b,value:1     key:e,value:2
                                                    //map.get(key)表示根据key值取value的值。
        }
         //遍历map集合的方法二:使用迭代器Iterator遍历
        Set keySet=map.keySet(); //获取键的集合
        Iterator it=keySet.iterator();
        while (it.hasNext()){
            Object key=it.next();
            Object vaule =map.get(key);
            System.out.println(key+":"+ vaule);
        }
    }
}
    • TreeMap:可根据key值实现默认排序。
public class Test3 {
    public static void main(String[] args) {
         Map<Integer,String> map= new TreeMap<Integer, String>();
        map.put(2,"a");
        map.put(1,"d");
        map.put(5,"h");
        map.put(3,"r");
        System.out.println(map);
    }
}/*输出:
{1=d, 2=a, 3=r, 5=h}
*/

//再测试:
        Map<String ,String> map1= new TreeMap<String, String>();

        map1.put("ae","a");
        map1.put("d","t");
        map1.put("a","y");
        map1.put("g","i");
        map1.put("1","ac");
        map1.put("8","a");

        System.out.println(map1);
/*输出:
{1=ac, 8=a, a=y, ae=a, d=t, g=i}
体会排序功能
*/

  • 工具类——Collections
import java.util.*;

public class Test4 {
    public static void main(String[] args) {
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(4);
        list.add(6);
        list.add(2);
        System.out.println(list);//[1, 4, 6, 2]

        //反转集合
        Collections.reverse(list);
        System.out.println(list);//[2, 6, 4, 1]

        //随机排序
     Collections.shuffle(list);
        System.out.println(list);//[2, 4, 1, 6]

        //list集合字典升序排列
        Collections.sort(list);
        System.out.println(list);//[1, 2, 4, 6]

        //指定交换集合中的几个元素
        Collections.swap(list,0,3);//调换第0 个元素和第三个元素
        System.out.println(list);

        //查找最大值,最新小值
        System.out.println(Collections.max(list));//6
        System.out.println(Collections.min(list));//1

        //返回指定元素出现的次数
        list.add(1);//在集合中再添加一个1;
        System.out.println(Collections.frequency(list, 1)); //2
        System.out.println(Collections.frequency(list, 2)); //2
        System.out.println(Collections.frequency(list, 3)); //0,集合中没有3

        // 用新的值替换所有旧值
        Collections.replaceAll(list,1,111);//把1换成111
        System.out.println(list);//[6, 2, 4, 111, 111]

    }
}

3.泛型

定义:限定集合只能存入指定类型的元素;

public class Test5{
    public static void main(String[] args){
        List list=new ArrayList//不使用泛型时,默认是Object类,即集合中可以存入任何类型的元素;
        List <String> lit = new ArrayList<String>(); //集合中只能存入String类型
		List <Ingeter> li = new ArrayList<Ingeter>();//集合中只能存入整型元素;
        li.add("name");//报错,是在编译期间发现的问题
    }
}

注意:泛型只在编译期有效,不会进入运行时段。

4.泛型的使用
  • 泛型类;
  • 泛型方法;
  • 泛型接口;
public class Test06 {
    /**
     *泛型类,名字T可以使用任意A,B,V...
     *一般用T,意为type,先在类名后面加<T>,,表示他是一个泛指类,然后在new的时候具体使用
     *意义:在面向对象时(new 对象时),达到将对象类型限定(指定对象类型)的效果。
     */
}
class A<T>{
    private T key;
    public void setKey(T key){
        this.key=key;
    }
    public T getKey(){
        return this.key;
    }
    public static void main(String[] args) {
        A<String> a1=new A <String>();//在new A对象时指定数据类型是String
        a1.setKey("xxxx");//对象使用setKey(T key)方法,中的key形参就是String类型
        String s=a1.getKey();//T getKey()返回的对象也是String类型;

        A<Integer> a2= new A<Integer>();//限定对象类型为整数型
        a2.setKey(1);
       // a1=a2;报错,类型不同不能赋值
    }
}

====================================分割线==========================================
/**
 * 泛型接口
 */
public class Test07 {  //测试类,先看下面下面接口的代码
    public static void main(String[] args) {
        B1<Object> b1=new B1<Object>();//B1没有限定类型,就可以使用任意类型
        B1<String> b2=new B1<String>();
         //不同的是,new确定好泛型类型的对象时,就不能再指定泛型了,因为前面已经指定过
        B2 b3=new B2();
        // B2<String> b3=new B2<String>();这样反而报错。
    }
}
interface IB<T>{ //接口IB
    T test(T t); //接口方法
}
class B1 <T> implements IB<T>{ //未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
//如果不声明泛型,如:class B1 implements IB<T>,编译器会报错:"Unknown class"
    @Override
    public T test(T t) {
        return t;
    }
}
    class B2 implements IB<String>{ //实现接口时指定接口的泛型具体数据类型,实现类B2后面就可以不用写类型<String>,
        @Override
        public String test(String s) {//并且实现类中所有方法的类型和返回类型都变为和泛型一样
            return null;
        }
    }
 
===================================分割线===========================================

/**
 * 泛型方法
 */
class C<T>{ //定义一个泛型类;
    /**
     * 无返回值的泛型方法
     */
    public <T>void test(T s){
        T t=s;
    }

    /**
     * 有返回值的泛型方法
     */ public <T> T test1(T s){
        return s;
    }

    /**
     * 型参为可变参数的泛型方法
     */
    public <T> void test2 (T...args){
         for(T tt:args){
             System.out.println(tt);
         }
   }

    public static void main(String[] args) {
        C <Object>c=new <Object> C();
        //泛型方法:在调用之前没有固定的数据类型
        //调用时传入的参数是什么类型就会把泛型改为什么类型,自动的
        c.test(11);//传递的参数是integer,泛型就变成integer,返回值也是变为Integer
        c.test("wowo" );//传递的参数是String,泛型就变成String,返回值也是变为String
        c.test(true);//...
    }
}
    
  • 泛型通配符“?”的使用
/**
 * 通配符?的使用
 *1:不确定集合中的元素具体的数据类型
 */
public class Tast09 {
    public static void main(String[] args) {
        A1 a=new A1();
        List<String > l1=new ArrayList<String>();
        a.test(l1);
        List<Integer> l2=new ArrayList<Integer>();
        a.test(l2);
    }
}
class A1{
 public void test(List<?> list){//test方法需要一个list集合的参数,不确定list存储的类型是什么
    }
}

/**
 * 通配符?的使用
 *2:有限制的通配符
 */
public class Tast09 {
    public static void main(String[] args) {
          A1 a=new A1();
        List<C1> Lc=new ArrayList<C1>();
        a.test(Lc);
        List< D1> Ld=new ArrayList<D1>();
        a.test(Ld);
        List< B3> Le=new ArrayList<B3>();
        //a.test(Le);报错,B3是C1的父类,不在范围内,所以不能添加le集合作为test的形参
  }
}
class A1{
    public void test(List<? extends C1> list){//list的参数元素数据类型的范围是在C1及其子类中
    }
}

class A2{}
class B3 extends A1{}
class C1 extends B3{}
class D1 extends C1{}
/**
 * public void test(List<? super C1> list)时表示只允许泛型为C1及其C1的父类才能使用,和上面演示一样
 * <? extends Comparable>只允许泛型为实 现Comparable接口的实现类的引用调用
 */

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值