java基础知识超全面参考黑马的ppt

java基础

java基础知识

数据类型

基本数据类型(8):byteshortintlongfloatdoublecharboolean

引用数据类型(3):数组、类、接口

byte中最大值为127最小值为-128,整数类型不能是小数。

float类型后面数值必须跟f同理long类型后面必须跟l因为在java中默认的整数为int,小数为double

自动类型转换:低级别-->高级别
强制类型转换:高级别-->低级别

算术表达式中包含不同的基本数据类型的值的时候,整个算术表达式的类型会自动进行提升。
提升规则:
byte类型,short类型和char类型将被提升到int类型,不管是否有其他类型参与运算。

整个表达式的类型自动提升到与表达式中最高等级的操作数相同的类型
等级顺序:byte,short,char --> int --> long --> float --> double

在这里插入图片描述

标识符

命名规则由数字,字母 ,下划线和$组成,不能以数字字开头,不能是java的关键字
注意:
  1.数字不可以开头
  2.不可以使用关键字

运算符

 &    不管前面是不是false都会执行后面
 
 &&   如果前面是false就不会再执行后面的
 
 逻辑与&,无论左边真假,右边都要执行。 
 
短路与&&,如果左边为真,右边执行;如果左边为假,右边不执行。
 
逻辑或|,无论左边真假,右边都要执行。 

短路或||,如果左边为假,右边执行;如果左边为真,右边不执行

自增自减运算符

++-- 既可以放在变量的后边,也可以放在变量的前边。

单独使用的时候, ++-- 无论是放在变量的前边还是后边,结果是一样的。
 
参与操作的时候,如果放在变量的后边,先拿变量参与操作,后拿变量做++或者--。
 
参与操作的时候,如果放在变量的前边,先拿变量做++或者--,后拿变量参与操作

三种循环的区别

for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)

 do...while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)
 
  for循环和while的区别 条件控制语句所控制的自增变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了
  
   条件控制语句所控制的自增变量,对于while循环来说不归属其语法结构中,在while循环结束后,该变 量还可以继续使用 
   
   死循环(无限循环)的三种格式 
   1. for(;;){
    
    } 
   2. while(true){
    
    }
   3. do {
    
    } while(true); 

跳转控制语句(break)  
跳出循环,结束循环 

跳转控制语句(continue)
 跳过本次循环,继续下次循环 
 
注意: continue只能在循环中进行使用!break可以在循环和switch里面使用

方法

 参数为变量是值的传递,改变形参的值,实参不受影响
 参数为数组,传递的是地址(引用传递),形参改变,实参也会改变
 基础数据类型作为方法的参数时,改变形参的值,实参不会改变。
 引用数据类型作为方法的参数时,改变形参的值,实参值会改变
 
 基本数据类型的参数,形式参数的改变,不影响实际参数 
 每个方法在栈内存中,都会有独立的栈空间,方法运行结束后就会弹栈消失

对于引用类型的参数,形式参数的改变,影响实际参数的值
引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法 弹栈,堆内存中的数据也已经是改变后的结果

方法的重载

 很多个方法可以拥有相同的方法名,但传的参数列表不同
 1.方法的名称必须相同
 2.列表参数必须不同
 3.方法的返回类型可以相同,也可以不同
 仅仅返回类型不同,不足以称作方法的重载

方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载
多个方法在同一个类中
多个方法具有相同的方法名 
多个方法的参数不相同,类型不同或者数量不同 

重载仅对应方法的定义,与方法的调用无关,调用方式参照标准格式 重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两 个方法是否相互构成重载

一些常用java开发软件的快捷键


eclipse的快捷键
shift + alt + r :把某个变量名或单词全部替换掉

idea的快捷键
ctrl + alt + l  整理代码格式
ctrl + alt + v 自动补全前面的代码或者加.var
Ctrl + F 在当前文件进行文本查找
Ctrl + R 在当前文件进行文本替换
Ctrl + Z 撤销 
Ctrl + Shift + Z 取消撤销
Ctrl + O 选择可重写的方法 
Ctrl + /  注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 
Ctrl + Shift + /	代码块注释 
Alt + Enter IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同
Alt + Insert	代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等
Ctrl + Alt + L 格式化代码,可以对当前文件和整个包目录使用 
Ctrl + Alt + O  优化导入的类,可以对当前文件和整个包目录使用 
Ctrl + Shift + F 根据输入内容查找整个项目 或 指定目录内文件
Ctrl + Shift + R  根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件
Ctrl + Shift + Enter 自动结束代码,行末自动添加分号 

类与对象

类与对象的概念

1.类是一组属性相同,方法相同的对象的集合,对象是类的具体化
2.对象具有类所有的特征,类拥有的,对象就拥有
3.类与对象是相对的

类:类是对现实生活中一类具有共同属性和行为的事物的抽象 
对象:是能够看得到摸的着的真实存在的实体 简单理解:类是对事物的一种描述,对象则为具体存在的事物 

对象的使用

创建对象的方法

    类名    对象名 = new 类名();

对象的属性和方法的调用

  对象名.属性
  对象名.方法()

构造方法

1.没有返回值,并且方法名与类名相同  

2.所有的类都有一个默认的构造方法,用户一旦自己声明构造方法时,原本默认的构造方法失效,构造方法允许的存在多个

构造方法作用

用来实例化对象,功能:主要是完成对象数据的初始化 

构造方法的创建
如果没有定义构造方法,系统将给出一个默认的无参数构造方法 如果定义了构造方法,系统将不再提供默认的构造 方法

构造方法的重载
如果自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法

推荐的使用方式
无论是否使用,都手工书写无参数构造方法

重要功能
可以使用带参构造,为成员变量进行初始化

this关键字

this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)

 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量 
 
 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
 
 this代表当前调用方法的引用,哪个对象调用的方法,this就代表哪一个对象

1.this调用本类中的属性,也就是类中的成员变量
2.this调用本类中的方法
3.this调用本类中的构造方法,调用是放在首行。

方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量 

方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量

成员变量和局部变量的区别

类中位置不同:
              成员变量(类中方法外)
              局部变量(方法内部或方法声明上) 
              
内存中位置不同:
               成员变量(堆内存)
               局部变量(栈内存)
                
生命周期不同:
             成员变量(随着对象的存在而存在,随着对象的消失而消失)
             局部变量(随着方法的调用而 存在,醉着方法的调用完毕而消失) 
             
初始化值不同:
            成员变量(有默认初始化值)
            局部变量(没有默认初始化值,必须先定义,赋值才能使用)


封装

private是一个修饰符,可以用来修饰成员(成员变量,成员方法)

 被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用,提供相 应的操作
 
  提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰 
  提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰 
  
封装概述 是面向对象三大特征之一(封装,继承,多态) 是面向对象编程语言对客观世界的模拟,客观世界 里成员变量都是隐藏在对象内部的,外界是无法直接操作的

封装原则 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏 信息的操作和访问 成员变量private,提供对应的getXxx()/setXxx()方法

封装好处 通过方法来控制成员变量的操作,提高了代码的安全性 把代码用方法进行封装,提高了代码的复用 性

继承

继承的概念

继承就是子类继承父类的特征和行为,使得子类具有父类的相同属性

继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及 追加属性和方法

实现继承的格式 继承通过extends实现 
格式:
class 子类 extends 父类 {
    
     }

public class Fu {
    
         
public void show() {
    
             
System.out.println("show方法被调用");     
} 
} public class Zi extends Fu {
    
         
public void method() {
    
             
System.out.println("method方法被调用");     
} 
} public class Demo {
    
         
public static void main(String[] args) {
    
    
         //创建对象,调用方法         
         Fu f = new Fu();         
         f.show();          
          Zi z = new Zi();         
          z.method();         
          z.show();     
 } 
                                                     }

继承的特点

继承鼓励类的重用
继承可以多层继承
一个类只能继承一个父类,java只支持单继承
父类中privatedefault修饰的不能被继承
构造方法不能被继承,只能调用

继承带来的好处与弊端

继承的好处
继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。

继承好处 提高了代码的复用性(多个类相同的成员可以放到同一个类中) 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)

继承弊端
继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削 弱了子类的独立性

继承的应用场景: 使用继承,需要考虑类与类之间是否存在is..a的关系,不能盲目使用继承 is..a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类

继承中变量的访问特点

在子类方法中访问一个变量,采用的是就近原则。
1. 子类局部范围找 
2.  子类成员范围找 
3.  父类成员范围找 
4.  如果都没有就报错(不考虑父亲的父亲…)

继承中构造方法的访问特点

注意:子类中所有的构造方法默认都会访问父类中无参的构造方法
 
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化, 
原因在于,每一个子类构造方法的第一条语句默认都是:super()
 
问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?

1. 通过使用super关键字去显示的调用父类的带参构造方法 

2. 在父类中自己提供一个无参构造方法

继承中成员方法的访问特点

1.通过子类对象访问一个方法
3. 子类成员范围找 
4. 父类成员范围找 
5. 如果都没有就报错(不考虑父亲的父亲…)

Java中继承的注意事项

 Java中类只支持单继承,不支持多继承(接口支持多继承)
 
 错误范例:class A extends B, C {
    
     }
 Java中类支持多层继承

super关键字

1.super关键字来访问父类成员
2.super只能出现在子类的方法和构造方法中
3.super调用构造方法时,只能是第一句
4.super不能访问父类的privae成员

this&super关键字:

this:代表本类对象的引用 
super:代表父类存储空间的标识(可以理解为父类对象引用) 

thissuper的使用分别
成员变量: 
this.成员变量    -   访问本类成员变量
super.成员变量 -   访问父类成员变量

成员方法: 
this.成员方法  - 访问本类成员方法
super.成员方法 - 访问父类成员方法

构造方法:
 this()  -  访问本类构造方法 
super()  -  访问父类构造方法

重写

方法重写概念

子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样) 

方法重写的应用场景

通过使用super关键字去显示的调用父类的带参构造方法 
在父类中自己提供一个无参构造方法
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了 父类的功能,又定义了子类特有的内容 

3、Override注解
用来检测当前的方法,是否是重写的方法,起到【校验】的作用

方法重写的注意事项

 私有方法不能被重写(父类私有成员子类是不能继承的) 
 
子类方法访问权限不能更低(public >protected> 默认 > 私有)

发生在父子关系中,子类覆盖父类方法时,这种方法就叫做重写,要求方法名,参数,都必须一样,返回值可以类型相同或者是子类,子类权限的修饰符不能比父类小

权限修饰符

在这里插入图片描述

package

包的概念

包就是文件夹,用来管理类文件的

包的定义格式

package 包名; (多级包用.分开)
例如:package com.blb.demo;

带包编译&带包运行

带包编译:javac –d . 类名.java
例如:javac -d . com.blb.demo.HelloWorld.java

带包运行:java 包名+类名
例如:java com.blb.demo.HelloWorld

import

导包的意义

使用不同包下的类时,使用的时候要写类的全路径,写起来太麻烦了
为了简化带包的操作,Java就提供了导包的功能

导包的格式
格式:import 包名;
范例:import java.util.Scanner;

final关键字

1.修饰变量时,定义时必须赋值,被修饰的变量不可变,一旦赋了储值就不能重新赋值

2.修饰方法 该方法不能被子类重写但是可以被重载

3.修饰类,该类不能被继承,比如math,string类

fianl关键字的作用 final代表最终的意思,可以修饰成员方法,成员变量,类 final修饰类、方法、变量的效果 fianl修饰类:该类不能被继承(不能有子类,但是可以有父类) 
final修饰方法:该方法不能被重写
final修饰变量:表明该变量是一个常量,不能再次赋值 

final修饰局部变量

fianl修饰基本数据类型变量
final 修饰指的是基本类型的数据值不能发生改变

final修饰引用数据类型变量
final 修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的

static关键字

static的概念 static关键字是静态的意思,可以修饰【成员方法】,【成员变量】 
static修饰的特点 
 被类的所有对象共享,这也是我们判断是否使用静态关键字的条件 
可以通过类名调用当然,也可以通过对象名调用【推荐使用类名调用】

1.static关键字用来声明独立于对象的静态变量
2.静态变量也被称作为类变量(归类所有),局部变量不能被声明为static变量
3.static关键字用来声明独立于对象的静态方法,静态方法不能使用非静态变量(非静态变量是属于对象的)
在静态方法中不能访问非静态变量(动态变量)和非静态方法
类所有的方法和属性,它的对象一定会有

static的访问特点

非静态的成员方法
能访问静态的成员变量 
能访问非静态的成员变量 
能访问静态的成员方法 
能访问非静态的成员方法
静态的成员方法
能访问静态的成员变量 
能访问静态的成员方法

总结成一句话就是:
静态成员方法只能访问静态成员

静态变量的特点与区别

静态变量全局唯一,为所有的对象共用,修改它的值,其他对象使用该变量时,值也会改变

非静态变量,每个对象持有一份,是独立的,修改对象的值不会影响其他对象的该值。

多态

什么是多态

同一个对象,在不同时刻表现出来的不同形态

多态的前提

要有继承或实现关系 要有方法的重写 要有父类引用指向子类对象

多态中的成员访问特点

成员访问特点
成员变量
  编译看父类,运行看父类
  或者编译看左边,运行也看左边
  
成员方法
  编译看父类,运行看子类
  或者编译看左边,运行看右边(因为方法有重写)

多态的好处和弊端

好处
  提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作
  
弊端
  不能使用子类的特有成员 

多态中的转型

向上转型
  父类引用指向子类对象就是向上转型
  
向下转型
  格式:子类型 对象名 = (子类型)父类引用;

抽象类

当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了!

在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!

抽象类的特点

抽象类和抽象方法必须使用 abstract 关键字修饰
 public abstract class 类名 {
    
    }  
 public abstract void eat();
 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
 
抽象类不能实例化
  抽象类如何实例化呢?参照多态的方式,通过子类对象实例化,这叫抽象类多态
抽象类的子类

  要么重写抽象类中的所有抽象方法
  要么是抽象类 

抽象类的成员特点

成员变量
既可以是变量 也可以是常量

构造方法
空参构造 有参构造

成员方法
抽象方法 普通方法

接口

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。

接口的特点

接口用关键字interface修饰

类实现接口用implements表示

public class 类名 implements 接口名 {
    
    }

接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态。
  多态的形式:具体类多态,抽象类多态,接口多态。
接口的子类
  要么重写接口中的所有抽象方法
  要么子类也是抽象类 
  
 Java中的接口更多的体现在对行为的抽象

接口的成员特点

 成员变量
  只能是常量   默认修饰符:public static final
  
构造方法
  没有,因为接口主要是扩展功能的,而没有具体存在
  
成员方法
  只能是抽象方法
  默认修饰符:public abstract

类和接口的关系

类与类的关系
  继承关系,只能单继承,但是可以多层继承
  
类与接口的关系
  实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
  
接口与接口的关系
  继承关系,可以单继承,也可以多继承 

抽象类和接口的区别

成员区别

抽象类
变量,常量;有构造方法;有抽象方法,也有非抽象方法
接口
常量;抽象方法

关系区别

类与类
继承,单继承
类与接口
实现,可以单实现,也可以多实现
接口与接口
继承,单继承,多继承

设计理念区别

抽象类
对类抽象,包括属性、行为
接口
对行为抽象,主要是行为

类名作为形参和返回值

1、类名作为方法的形参
方法的形参是类名,其实需要的是该类的对象
实际传递的是该对象的【地址值】

 2、类名作为方法的返回值
方法的返回值是类名,其实返回的是该类的对象
实际传递的,也是该对象的【地址值】

抽象类作为形参和返回值

抽象类作为形参和返回值
方法的形参是抽象类名,其实需要的是该抽象类的子类对象 

方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

接口名作为形参和返回值

方法的形参是接口名,其实需要的是该接口的实现类对象

 方法的返回值是接口名,其实返回的是该接口的实现类对象

内存关系

多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自的内存区域
中,成员方法多个对象共用的 一份 

当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的) 只要有
任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,
都是修改后的数据。 

内部类

内部类概念

 在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类

内部类定义格式

    /* 格式:          
      			class 外部类名{     
       			 修饰符 class 内部类名{                    }        
       			   } 
       		 */ 
       			    
       			public class Outer {
    
       
       			       public class Inner
       			        {
    
                  
       			        } 
       			  }

内部类的访问特点

内部类可以直接访问外部类的成员,包括私有 

外部类要访问内部类的成员,必须创建对象
  /*内部类访问特点:         
  内部类可以直接访问外部类的成员,包括私有         
  外部类要访问内部类的成员,必须创建对象 
   */ 
   public class Outer {
    
         
   private int num = 10;     
   public class Inner {
    
             
   public void show() {
    
                 
   System.out.println(num);         
   }     
   }    
    public void method() 
    {
    
             
    Inner i = new Inner();         
    i.show();     
    } 
    }

成员内部类

在类中方法,跟成员变量是一个位置
外界创建成员内部类格式 

格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象; 
举例:Outer.Inner oi = new Outer().new Inner();

成员内部类的推荐使用方案
将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有 化之后,再提供一个可以让外界调用的方法,方法内部创建内部类对象并调用

class Outer 
{
    
         
private int num = 10;     
private class Inner {
    
             
public void show() {
    
                 
System.out.println(num);         
 }     
}     
public void method() {
    
             
Inner i = new Inner();         
i.show();     
 } 
} 
public class InnerDemo {
    
         
public static void main(String[] args) {
    
     
//Outer.Inner oi = new Outer().new Inner();          
//oi.show();                  
Outer o = new Outer();         
o.method();     
 } 
}

局部内部类

局部内部类是在方法中定义的类
局部内部类方式方式
局部内部类,外界是无法直接使用,
需要在方法内部创建对象并使用 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
class Outer {
    
         
private int num = 10;     
public void method() {
    
             
int num2 = 20;         
class Inner {
    
                 
public void show() {
    
                     
System.out.println(num);                 
System.out.println(num2);             
 }         
}         
Inner i = new Inner();         
i.show();     
 } 
} 
public class OuterDemo {
    
         
public static void main(String[] args) 
{
    
             
Outer o = new Outer();         
o.method();     
 } 
}

匿名内部类

匿名内部类的前提
存在一个类或者接口,这里的类可以是具体类也可以是抽象类
匿名内部类的格式 格式:new 类名 ( ) {
    
     重写方法 } new 接口名 ( ) {
    
     重写方法 }

举例:

new Inter(){
    
        
 @Override     
 public void method()
 {
    
    } 
 } 
匿名内部类的本质
本质:是一个继承了该类或者实现了该接口的子类匿名对象
匿名内部类的细节
匿名内部类可以通过多态的形式接受
Inter i = new Inter(){
    
       
@Override     
public void method()
 {
    
                  
 } 
}
interface Inter{
    
         
void method(); 
}   
class Test{
    
         
public static void main(String[] args){
    
             
new Inter(){
    
                 
@Override             
public void method(){
    
                     
System.out.println("我是匿名内部类");             
}         
}.method(); // 直接调用方法       
} 
}

异常

在这里插入图片描述

JVM默认处理异常的方式

如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤: 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台 程序停止执行

try-catch方式处理异常

 try 
   {
    
        
   可能出现异常的代码; 
} 
catch(异常类名 变量名) 
{
    
        异常的处理代码; 
}

程序从 try 里面的代码开始执行 出现异常,就会跳转到对应的 catch 里面去执行 执行完毕之后,程序还可以继续往下执行

在这里插入图片描述

编译时异常

都是Exception类及其子类 必须显示处理,否则程序就会发生错误,无法通过编译

运行时异常

都是RuntimeException类及其子类 无需显示处理,也可以和编译时异常一样处理
这个throws格式是跟在方法的括号后面的
编译时异常必须要进行处理,两种处理方案:try…catch …或者 throws,如果采用 throws 这种方案, 将来谁调用谁处理
运行时异常可以不处理,出现问题后,需要我们回来修改代码

在这里插入图片描述

自定义异常

public class ScoreException extends Exception {
    
    
 
    public ScoreException() {
    
    }
 
    public ScoreException(String message) {
    
           
     super(message);    
     }
 
}
public class Teacher {
    
        
public void checkScore(int score) throws ScoreException {
    
            if(score<0 || score>100) {
    
     
       throw new ScoreException("你给的分数有误,分数应该在0-100之间");        } else {
    
                
       System.out.println("成绩正常");        
       }    
       } 
       }
public class Demo {
    
        
public static void main(String[] args) {
    
            
Scanner sc = new Scanner(System.in);        
System.out.println("请输入分数:");
 int score = sc.nextInt();
 
    Teacher t = new Teacher();        
    try {
    
                
    t.checkScore(score);        
    } catch (ScoreException e) {
    
                
    e.printStackTrace();        
    }    
    } 
    }

常用类

Random产生随机数
使用步骤:

  1. 导入包 import java.util.Random;
    1. 创建对象 Random r = new Random();
    1. 产生随机数 int num = r.nextInt(10); 解释: 10代表的是一个范围,如果括号写10,产生的随机数就是0-9,括号写20,参数的随机数则是0-19
      左闭右开

Math类

1、Math类概述 Math 包含执行基本数字运算的方法 

2、Math中方法的调用方式 Math类中无构造方法,但内部的方法都是静态的,则可以通过   类名.进行调用

在这里插入图片描述

abs

返回参数的绝对值,参数传入一个整数

import java.lang.Math.*;

public class math {
    
    

    public static void main(String[] args) {
    
    

        int a=-10;
        System.out.println(Math.abs(a));//10
    }

}

ceil floor

向上取整,向下取整,返回一个小数值等于一个整数

import java.lang.Math.*;

public class math {
    
    

    public static void main(String[] args) {
    
    

        Double a=12.23;

        System.out.println(Math.ceil(a)); //13.0 向上取,返回的是double类型

        System.out.println(Math.floor(a)); //12.0 向下取,返回的是double类型
    }

}

round

四舍五入,返回一个整数

import java.lang.Math.*;

public class math {
    
    

    public static void main(String[] args) {
    
    

        Double a=12.23;

        System.out.println(Math.round(a)); //12 返回一个整数
    }

}

pow

返回a的b次幂,参数和返回值都是小数

import java.lang.Math.*;

public class math {
    
    

    public static void main(String[] args) {
    
    

        System.out.println(Math.pow(2.0,3.0)); //8.0
    }

}

random

返回值为double 产生一个[0.0,1.0)随机数

import java.lang.Math.*;

public class math {
    
    

    public static void main(String[] args) {
    
    

        System.out.println(Math.random());//产生一个[0,1)随机数
    }

}

System类

在这里插入图片描述
在控制台输出1-10000,计算这段代码执行了多少毫秒

public class SystemDemo {
    
         
public static void main(String[] args) {
    
            
 // 获取开始的时间节点        
  long start = System.currentTimeMillis();         
  for (int i = 1; i <= 10000; i++) {
    
                 
  System.out.println(i);         
  }        
   // 获取代码运行结束后的时间节点         
   long end = System.currentTimeMillis();         
   System.out.println("共耗时:" + (end -start) + "毫秒");     
   } 
   }

Object类

Object类概述 Object 是类层次结构的根,每个类都可以将 Object 作为超类。所有类都直接或者间接的继承自该类, 换句话说,该类所具备的方法,所有类都会有一份

查看方法源码的方式 选中方法,按下Ctrl + B 

重写toString方法的方式 1. Alt + Insert 选择toString 
在类的空白区域,右键 -> Generate -> 选择toString toString方法的作用:
以良好的格式,更方便的展示对象中的属性值

equals方法的作用 用于对象之间的比较,返回truefalse的结果 
举例:s1.equals(s2);    s1和s2是两个对象 重写equals方法的场景
不希望比较对象的地址值,想要结合对象属性进行比较的时候。
 
重写equals方法的方式
 alt + insert  选择equals() and hashCode(),IntelliJ Default,一路next,finish即可 
在类的空白区域,右键 -> Generate -> 选择equals() and hashCode(),后面的同上

string类

String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例。
也就是说,Java 程序 中所有的双引号字符串,都是 String 类的对象。

String 类在 java.lang 包下,所以使用的时候不需要导包

字符串不可变,它们的值在创建后不能被更改 虽然 String 的值是不可变的,
但是它们可以被共享 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] ) 

在这里插入图片描述

在这里插入图片描述

字符串的创建


 //public String():创建一个空白字符串对象,不含有任何内容        
		String s1 = new String();        
		System.out.println("s1:" + s1);
 
 //public String(char[] chs):根据字符数组的内容,来创建字符串对象        
		char[] chs = {
    
    'a', 'b', 'c'};        
		String s2 = new String(chs);        
		System.out.println("s2:" + s2);
 
 //public String(byte[] bys):根据字节数组的内容,来创建字符串对象        
		byte[] bys = {
    
    97, 98, 99};       
		 String s3 = new String(bys);        
		System.out.println("s3:" + s3);
 
//String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc       
		 String s4 = "abc";        
		System.out.println("s4:" + s4);    } }

equals

public boolean equals(String s)     比较两个字符串内容是否相同、区分大小写

length

public int length()   返回字符串的长度

charAt

public char charAt(int index)  返回索引处的char

字符串地址和内容的比较

public class StringDemo02 {
    
        
public static void main(String[] args) {
    
            
//构造方法的方式得到对象        
char[] chs = {
    
    'a', 'b', 'c'};       
 String s1 = new String(chs);        
String s2 = new String(chs);
 
 
        //直接赋值的方式得到对象        
String s3 = "abc";        
String s4 = "abc";
 
        //比较字符串对象地址是否相同        
ystem.out.println(s1 == s2); //new出来的地址值不一样 false       
System.out.println(s1 == s3); //fasle       
System.out.println(s3 == s4);//直接赋值的是在常量池,内容一样地址也一样 true       
System.out.println("--------");
 
        //比较字符串内容是否相同        
System.out.println(s1.equals(s2));  //内容都相同      
System.out.println(s1.equals(s3));       
 System.out.println(s3.equals(s4));    
 } 
}

字符串的遍历

public class teststring {
    
    

    public static void main(String[] args) {
    
    
        String str="dyk666";
        for(int i=0;i<str.length();i++)
        {
    
    
            System.out.println(str.charAt(i));

        }
    }
}

StringBuilder

StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder 对象中的 内容是可变的 

stringBuilder类和String类的区别

String类:内容是不可变的 
StringBuilder类:内容是可变的 

在这里插入图片描述
在这里插入图片描述

import java.util.ArrayList;
import java.util.List;

public class ArrayList01 {
    
    


    public static void main(String[] args) {
    
    

        StringBuilder sb=new StringBuilder("hello");
        System.out.println(sb);//hellow
        StringBuilder sb1= sb.append("world");
        System.out.println(sb1==sb);//true append返回对象本身
        sb.reverse();
        System.out.println(sb);//dlrowwolleh
    }

}

StringBuilder和String相互转换

StringBuilder转换为String 

public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String 

String转换为StringBuilder 
public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder 

在这里插入图片描述

ArrayList

什么是集合 
提供一种存储空间可变的存储模型,存储的数据容量可以发生改变 ArrayList集合的特点
 
底层是数组实现的,长度可以变化 

泛型的使用 用于约束集合中存储元素的数据类型 

在这里插入图片描述

add

public boolean add(E e) 将指定的元素追加到此集合的末尾

public void add(int index,E element) 在此集合中的指定位置插入指定的元素

import java.util.ArrayList;

public class Arraylist02 {
    
    

    public static void main(String[] args) {
    
    
        //public boolean add(E e) 将指定的元素追加到此集合的末尾

        ArrayList<String> list=new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("javase");

        System.out.println(list); //[hello, java, javase]

        //public void add(int index,E element) 在此集合中的指定位置插入指定的元素
        list.add(1,"dyk");
        System.out.println(list);//[hello, dyk, java, javase]

        list.add(5,"hehe");//java.lang.IndexOutOfBoundsException
    }

}

remove

public boolean remove(Object o) 删除指定的元素,返回删除是否成功

public E remove(int index) 删除指定索引处的元素,返回被删除的元素

import java.util.ArrayList;

public class Arraylist02 {
    
    

    public static void main(String[] args) {
    
    

        ArrayList<String> list=new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("javase");

        System.out.println(list); //[hello, java, javase]

        //public boolean remove(Object o) 删除指定的元素,返回删除是否成功
        System.out.println(list.remove("javase"));//true
        
        System.out.println(list); //[hello, java]

        System.out.println(list.remove("python"));//false 不会报错,但也不会删除,因为不存在

        //public E remove(int index) 删除指定索引处的元素,返回被删除的元素

        System.out.println(list.remove(0)); //hello
        
        System.out.println(list.remove(5)); //报错 java.lang.IndexOutOfBoundsException

    }

}

set

public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素

import java.util.ArrayList;

public class Arraylist02 {
    
    

    public static void main(String[] args) {
    
    

        ArrayList<String> list=new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("javase");

        System.out.println(list); //[hello, java, javase]

        //public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
        list.set(0,"c++");
        System.out.println(list); //[c++, java, javase]

        list.set(5,"c++");//报错 java.lang.IndexOutOfBoundsException
    }

}

size

public int size() 返回集合中的元素的个数

import java.util.ArrayList;

public class Arraylist02 {
    
    

    public static void main(String[] args) {
    
    

        ArrayList<String> list=new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("javase");

        System.out.println(list); //[hello, java, javase]
 
    //public int size() 返回集合中的元素的个数
        System.out.println(list.size()); //3

    }

}

ArrayList 遍历

import java.util.ArrayList;

public class Arraylist02 {
    
    

    public static void main(String[] args) {
    
    

        ArrayList<String> list=new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("javase");

        for(int i=0;i<list.size();i++)
        {
    
    
         String s = list.get(i);
            System.out.println(s);
        }

        
    }

}

Arrays

在这里插入图片描述

基本类型包装类

基本类型包装类的作用 将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据 常用的操作之一:用于基本数据类型与字符串之间的转换

在这里插入图片描述
在这里插入图片描述

int转换为String 转换方式

方式一:直接在数字后加一个空字符串
方式二:通过String类静态方法valueOf()

public class IntegerDemo {
    
        
public static void main(String[] args) {
    
            
//int --- String        
int number = 100;        
//方式1        
String s1 = number + "";        
System.out.println(s1);        
//方式2        
//public static String valueOf(int i)        
String s2 = String.valueOf(number);        
System.out.println(s2);        
System.out.println("--------");    
} 
}

String转换为int 转换方式

方式一:先将字符串数字转成Integer,再调用valueOf()方法
方式二:通过Integer静态方法parseInt()进行转换

public class IntegerDemo {
    
        
 public static void main(String[] args) {
    
            
 //String --- int        
 String s = "100";        
 //方式1:String --- Integer --- int       
  Integer i = Integer.valueOf(s);        
  //public int intValue()        
  int x = i.intValue();        
  System.out.println(x);       
   //方式2        
   //public static int parseInt(String s)       
    int y = Integer.parseInt(s);        
    System.out.println(y);    
   } 
 }

自动装箱
把基本数据类型转换为对应的包装类类型
自动拆箱
把包装类类型转换为对应的基本数据类型

Integer i = 100;  // 自动装箱 i += 200;         
// i = i + 200;  i + 200 自动拆箱;i = i + 200; 是自动装箱

时间日期类

在这里插入图片描述
在这里插入图片描述
SimpleDateFormat类概述 SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。 我们重点学习日期格式化和解析

在这里插入图片描述
SimpleDateFormat类的常用方法
格式化(从Date到String) public final String format(Date date):将日期格式化成日期/时间字符串

解析(从String到Date) public Date parse(String source):从给定字符串的开始解析文本以生成日期

public class SimpleDateFormatDemo {
    
        
public static void main(String[] args) throws ParseException {
    
            
//格式化:从 Date 到 String        
Date d = new Date();         
SimpleDateFormat sdf = new SimpleDateFormat();        
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");        
String s = sdf.format(d);        
System.out.println(s);        
System.out.println("--------");
 
 //从 String 到 Date        
String ss = "2048-08-09 11:11:11";        
 SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        
 Date dd = sdf2.parse(ss);        
 System.out.println(dd);   
     } 
     }

Calendar类

概述 Calendar 为特定瞬间与一组日历字段之间的转换提供了一些方法,
并为操作日历字段提供了一些方法 Calendar 提供了一个类方法 getInstance 用于获取这种类型的一般有用的对象。 该方法返回一个Calendar 对象。 其日历字段已使用当前日期和时间初始化:
Calendar rightNow =Calendar.getInstance();
Calendar类常用方法

在这里插入图片描述

public class CalendarDemo {
    
        
public static void main(String[] args) {
    
            
//获取日历类对象        
Calendar c = Calendar.getInstance();
 
  //public int get(int field):返回给定日历字段的值        
  int year = c.get(Calendar.YEAR);        
  int month = c.get(Calendar.MONTH) + 1;        
  int date = c.get(Calendar.DATE);        
  System.out.println(year + "年" + month + "月" + date + "日");
 
        //public abstract void add(int field, int amount):根据日历的规则,将指定的时 间量添加或减去给定的日历字段        
        //需求1:3年前的今天       
         c.add(Calendar.YEAR,-3);        
         year = c.get(Calendar.YEAR);       
         month = c.get(Calendar.MONTH) + 1;        
         date = c.get(Calendar.DATE);         
         System.out.println(year + "年" + month + "月" + date + "日");
 
        //需求2:10年后的10天前 //        
        c.add(Calendar.YEAR,10);         
        c.add(Calendar.DATE,-10);        
         year = c.get(Calendar.YEAR);       
          month = c.get(Calendar.MONTH) + 1;        
          date = c.get(Calendar.DATE);       
           System.out.println(year + "年" + month + "月" + date + "日");
 
        //public final void set(int year,int month,int date):设置当前日历的年月日        
        c.set(2050,10,10);       
         year = c.get(Calendar.YEAR);        
         month = c.get(Calendar.MONTH) + 1;        
         date = c.get(Calendar.DATE);        
         System.out.println(year + "年" + month + "月" + date + "日");
 
    } 
    }

集合

List:是一个有序集合,可以放重复的数据
Set:是一个无序集合,不允许放重复的数据
Map:是一个无序集合,集合中包含一个键对象,一个值对象,键对象不允许重复,值对象可以重

在这里插入图片描述

在这里插入图片描述

Collection集合概述

是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素 JDK 不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
在这里插入图片描述

Collection集合的遍历

迭代器的介绍 迭代器,集合的专用遍历方式 Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;


public class IteratorDemo {
    
        

    public static void main(String[] args) {
    
            //创建集合对象        
        Collection<String> c = new ArrayList<>();

        //添加元素        
        c.add("hello");        
        c.add("world");        
        c.add("java");        
        c.add("javaee");

        //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到        
        Iterator<String> it = c.iterator();

        //用while循环改进元素的判断和获取        
        while (it.hasNext()) {
    
                
            String s = it.next();            
            System.out.println(s);      

        }  
    }

}

List集合概述和特点

List集合概述 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元 素,并搜索列表中的元素
与Set集合不同,列表通常允许重复的元素
List集合特点
有索引
可以存储重复元素
元素存取有序

在这里插入图片描述

 //迭代器方式        
         Iterator<Student> it = list.iterator();        
        while (it.hasNext()) {
    
                
            Student s = it.next();            
            System.out.println(s.getName() + "," + s.getAge());      
        }                
        // System.out.println("--------");

        //for循环方式        
        for (int i = 0; i < list.size(); i++) {
    
                
            Student s = list.get(i);            
            System.out.println(s.getName() + "," + s.getAge());      
        }

  }

并发修改异常

出现的原因
迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际 修改值不一致,则会出现:ConcurrentModificationException
解决的方案
用for循环遍历,然后用集合对象做对应的操作即可

public class ListDemo {
    
        

            public static void main(String[] args) {
    
            
                //创建集合对象        
                List<String> list = new ArrayList<String>();

        添加元素        
                list.add("hello");        
                list.add("world");        
                list.add("java");

        //遍历集合,得到每一个元素,看有没有"world"这个元素,如果有,我就添加一 个"javaee"元素,请写代码实现       
                Iterator<String> it = list.iterator();       
                while (it.hasNext()) {
    
               
                    String s = it.next();           
                    list.add("javaee");   //会报错,ConcurrentModificationException       
                }     
            }

        for(
            int i = 0; i<list.size();i++)

            {
    
              
                String s = list.get(i);
        if (s.equals("world")) {
    
                    
        list.add("javaee");          
            }      
            }
 
        //输出集合对象       
          System.out.println(list);  
        }
    }

ListIterator

通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器 用于允许程序员沿任一方向遍历的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

 //创建集合对象        
        List<String> list = new ArrayList<String>();
 
        //添加元素        
        list.add("hello");        
        list.add("world");        
        list.add("java");
 
        //获取列表迭代器        
        ListIterator<String> lit = list.listIterator();        
        while (lit.hasNext()) {
    
                
            String s = lit.next();            
            if (s.equals("world")) {
    
                    
                lit.add("javaee");          
            }      
        }
 
        System.out.println(list);

增强for循环

for(元素数据类型 变量名 : 数组/集合对象名) {
    
        循环体; }

List集合子类的特点

ArrayList集合 底层是数组结构实现,查询快、增删慢
LinkedList集合 底层是链表结构实现,查询慢、增删

LinkedList

在这里插入图片描述

import java.util.Iterator;
import java.util.LinkedList;
import java.util.zip.CheckedOutputStream;

public class listtest {
    
    
    public static void main(String[] args) {
    
    
        LinkedList<String> lk=new LinkedList<>();
        lk.add("hello");
        lk.add("world");
        lk.add("java");



        System.out.println("-------------");
        //public E getFirst() 返回此列表中的第一个元素
        String first = lk.getFirst();
        //public E getLast() 返回此列表中的最后一个元素
        String last = lk.getLast();
        System.out.println(first);
        System.out.println(last);
        //public void addFirst(E e) 在该列表开头插入指定的元素
        lk.addFirst("firstadd");
        //public void addLast(E e) 将指定的元素追加到此列表的末尾

        lk.addLast("lastadd");
        Iterator<String> it = lk.iterator();
        while (it.hasNext()){
    
    
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("---------");
        //public E removeFirst() 从此列表中删除并返回第一个元素

        lk.removeFirst();
        //public E removeLast() 从此列表中删除并返回最后一个元素

        lk.removeLast();

        Iterator<String> it2 = lk.iterator();
        while (it2.hasNext()){
    
    
            String s = it2.next();
            System.out.println(s);
        }
    }
}

Set集合

Set集合的特点
元素存取无序
没有索引、只能通过迭代器或增强for循环遍历
不能存储重复元素

public class SetDemo {
    
        
public static void main(String[] args) {
    
            
//创建集合对象        
Set<String> set = new HashSet<String>();
     //添加元素        
     set.add("hello");        
     set.add("world");        
     set.add("java");        
     //不包含重复元素的集合        
     set.add("world");
 
        //遍历        
        for(String s : set) 
        {
    
                System.out.println(s);        
        }    
} 
}

哈希值简介

是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
如何获取哈希值
Object类中的public int hashCode():返回对象的哈希码值
哈希值的特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同 获取哈希值的代码

HashSet集合保证元素唯一性的原理

1.根据对象的哈希值计算存储位置
如果当前位置没有元素则直接存入
如果当前位置有元素存在,则进入第二步
2.当前元素的元素和已经存在的元素比较哈希值
如果哈希值不同,则将当前元素进行存储
如果哈希值相同,则进入第三步
3.通过equals()方法比较两个元素的内容
如果内容不相同,则将当前元素进行存储
如果内容相同,则不存储当前元素

在这里插入图片描述
在这里插入图片描述

public class Student {
    
        
private String name;    
private int age;
 
    public Student() {
    
        }
 
    public Student(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 boolean equals(Object o) {
    
            
    if (this == o) return true;        
    if (o == null || getClass() != o.getClass()) return false;
 
        Student student = (Student) o;
 
        if (age != student.age) return false;        
        return name != null ? name.equals(student.name) : 
        student.name == null;    }
 
    @Override    public int hashCode() {
    
            
    int result = name != null ? name.hashCode() : 0;        
    result = 31 * result + age;        
    return result;    
    } 
    }

LinkedHashSet集合特点

哈希表和链表实现的Set接口,具有可预测的迭代次序 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
由哈希表保证元素唯一,也就是说没有重复的元素

TreeSet集合

TreeSet集合概述 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法 TreeSet():根据其元素的自然排序进行排序 TreeSet(Comparator comparator) :根据指定的比较器进行排序 没有带索引的方法,所以不能使用普通for循环遍历 由于是Set集合,所以不包含重复元素的集合

用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

public class Student implements Comparable<Student> {
    
        
private String name;    private int age;
 
    public Student() {
    
        }
 
    public Student(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(Student s) 
    {
    
     //        return 0;
     //        return 1; 
     //        return -1;       
      //按照年龄从小到大排序      
       int num = this.age - s.age;
        // 按照年龄从大到小排序   int num = s.age - this.age;        
        //年龄相同时,按照姓名的字母顺序排序 
        //如果不写这个,当年龄相同时再在treeset集合中添加元素时就添加不进去     
         int num2 = num==0?this.name.compareTo(s.name):num;        return num2;    
         } 
         }

用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

public class TreeSetDemo {
    
        
public static void main(String[] args) {
    
            
//创建集合对象        
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student> () 
{
    
                
@Override            
public int compare(Student s1, Student s2) {
    
                    
//this.age - s.age                
//s1,s2                
int num = s1.getAge() - s2.getAge();                
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;                return num2;            
}        
});
 
        //创建学生对象        S
        tudent s1 = new Student("xishi", 29);        
        Student s2 = new Student("wangzhaojun", 28);        
        Student s3 = new Student("diaochan", 30);        
        Student s4 = new Student("yangyuhuan", 33);
        Student s5 = new Student("linqingxia",33);        
        Student s6 = new Student("linqingxia",33);
 
        //把学生添加到集合        
        ts.add(s1);        
        ts.add(s2);        
        ts.add(s3);        
        ts.add(s4);        
        ts.add(s5);        
        ts.add(s6);
 
        //遍历集合        
        for (Student s : ts) {
    
                
        System.out.println(s.getName() + "," + s.getAge());       
         }    
        } 
      }

泛型

泛型概述 是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许
在编译时检测到非法的类型 它的本质是参数化类型,也就是说所操作的数据类型
被指定为一个参数。一提到参数,最熟悉的就是定义方 法时有形参,然后调用此
方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的
具 体的类型参数化,然后在使用/调用时传入具体的类型。这种参数类型可以用
在类、方法和接口中,分别被称 为泛型类、泛型方法、泛型接口

泛型定义格式 <类型>:指定一种类型的格式。这里的类型可以看成是形参 <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型的好处

把运行时期的问题提前到了编译期间
避免了强制类型转换

泛型类

修饰符 class 类名<类型> { }

public class Generic<T> {
    
        

private T t;
 public T getT() {
    
           
  return t;    
  }
public void setT(T t) {
    
            
this.t = t;    
} 
}

泛型方法

修饰符 <类型> 返回值类型 方法名(类型 变量名) { }

public class Generic {
    
        
public <T> void show(T t) {
    
            
System.out.println(t);    
  } 
}

泛型接口

修饰符 interface 接口名<类型> { }

泛型接口
public interface Generic<T> {
    
        
void show(T t); 
}

泛型接口实现类
public class GenericImpl<T> implements Generic<T> {
    
        
@Override   
 public void show(T t) {
    
            
 System.out.println(t);    
  } 
 }


类型通配符

作用
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符的分类 类型通配符:<?>
List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中 类型通

配符上限:<? extends 类型> List<? extends Number>:它表示的类型是Number或者其子类型
类型通配符下限:<? super 类型> List<? super Number>:它表示的类型是Number或者其父类型

public class GenericDemo {
    
        
public static void main(String[] args) {
    
            
//类型通配符:<?>        
List<?> list1 = new ArrayList<Object>();        
List<?> list2 = new ArrayList<Number>();       
 List<?> list3 = new ArrayList<Integer>();        
 System.out.println("--------");
 
        //类型通配符上限:<? extends 类型> 
        //   List<? extends Number> list4 = new ArrayList<Object>(); 
        //报错不能超过Number       
        List<? extends Number> list5 = new ArrayList<Number>();        
        List<? extends Number> list6 = new ArrayList<Integer>();        
        System.out.println("--------");
 
        //类型通配符下限:<? super 类型>       
         List<? super Number> list7 = new ArrayList<Object>();        
         List<? super Number> list8 = new ArrayList<Number>(); 
         //  List<? super Number> list9 = new ArrayList<Integer>();
         //报错不能小于Number
    } 
   }

可变参数

可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了 可变参数定义格式

修饰符 返回值类型 方法名(数据类型… 变量名) { }
可变参数的注意事项 这里的变量其实是一个数组 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

public static List asList(T… a):返回由指定数组支持的固定大小的列表
返回的集合不能做增删操作,可以做修改操作
List接口中有一个静态方法: public static List of(E… elements):返回包含任意数量元素的不可变列表
返回的集合不能做增删改操作 Set接口中有一个静态方法:
public static Set of(E… elements) :返回一个包含任意数量元素的不可变集合
在给元素的时候,不能给重复的元素
返回的集合不能做增删操作,没有修改的方法

public class ArgsDemo02 {
    
        
public static void main(String[] args) {
    
            
//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,"javaee");       
System.out.println(list);

   //public static <E> List<E> of(E... elements):返回包含任意数量元素的不可变列 表       
List<String> list = List.of("hello", "world", "java", "world"); 
list.add("javaee");//UnsupportedOperationException 
list.remove("java");//UnsupportedOperationException 
list.set(1,"javaee");//UnsupportedOperationException 
 System.out.println(list);
 
   //public static <E> Set<E> of(E... elements) :返回一个包含任意数量元素的不可 变集合 
Set<String> set = Set.of("hello", "world", "java","world"); //IllegalArgumentException        
Set<String> set = Set.of("hello", "world", "java");
 

set.add("javaee");//UnsupportedOperationException 
  set.remove("world");//UnsupportedOperationException
 
        System.out.println(set);    
} 
}

Map集合

interface Map<K,V> K:键的类型;V:值的类型

Map集合的特点
键值对映射关系
一个键对应一个值
键不能重复,值可以重复
元素存取无序

public class MapDemo01 {
    
        
public static void main(String[] args) {
    
            
//创建集合对象        
Map<String,String> map = new HashMap<String,String>();
 
        //V put(K key, V value) 将指定的值与该映射中的指定键相关联        
        map.put("itheima001","林青霞");        
        map.put("itheima002","张曼玉");        
        map.put("itheima003","王祖贤");       
         map.put("itheima003","柳岩");
 
        //输出集合对象        
        System.out.println(map);    
        } 
      }

在这里插入图片描述

在这里插入图片描述

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapTest {
    
    

    public static void main(String[] args) {
    
    

        HashMap<String, String> hm = new HashMap<>();
        //V put(K key,V value) 添加元素
        hm.put("郭靖", "黄蓉");
        hm.put("杨过", "小龙女");
        hm.put("张无忌", "赵敏");

        //V remove(Object key) 根据键删除键值对元素
//        System.out.println(hm.remove("杨过"));//小龙女返回键值对应的value
        //void clear() 移除所有的键值对元素
//        hm.clear();

        //boolean containsKey(Object key) 判断集合是否包含指定的键
        System.out.println(hm.containsKey("杨过"));//true;
        System.out.println(hm.containsKey("郭襄"));//false;
        //boolean containsValue(Object value) 判断集合是否包含指定的值
        System.out.println(hm.containsValue("小龙女"));//true
        System.out.println(hm.containsValue("尹志平"));//false

        // boolean isEmpty() 判断集合是否为空
        System.out.println(hm.isEmpty());//false
        //int size() 集合的长度,也就是集合中键值对的个数
        System.out.println(hm.size());//3

        //V get(Object key) 根据键获取值
        System.out.println(hm.get("杨过"));//小龙女
        //Set keySet() 获取所有键的集合

        Set<String> set = hm.keySet();
        for (String s : set) {
    
    
            System.out.println(s + " " + hm.get(s));
        }
        System.out.println("--------");
        //Collection values() 获取所有值的集合
        Collection<String> values = hm.values();
        for (String s : values) {
    
    
            System.out.println(s);
        }
        System.out.println("----------");
        //Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合
        Set<Map.Entry<String, String>> entries = hm.entrySet();
        for (Map.Entry<String, String> hs:entries){
    
    
            System.out.println(hs.getKey());
            System.out.println(hs.getValue());
        }
    }
}

集合嵌套之ArrayList嵌套HashMap

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class qiantao {
    
    
    public static void main(String[] args) {
    
    
         ArrayList<HashMap<String,String>> arr = new ArrayList<>();

        HashMap<String, String> mp = new HashMap<>();
         mp.put("杨过","小龙女");
         mp.put("郭靖","黄蓉");
         arr.add(mp);

        HashMap<String, String> mp1 = new HashMap<>();
        mp.put("孙策","大乔");
        mp.put("周瑜","小乔");
        arr.add(mp1);

        HashMap<String, String> mp2 = new HashMap<>();
        mp.put("曾小贤","胡一菲");
        mp.put("吕子乔","陈美嘉");
        arr.add(mp2);


        //遍历1
        for (HashMap<String, String> hm:arr){
    
    
             Set<String> set = hm.keySet();
             for (String s:set){
    
    
                 System.out.println(s+"  "+hm.get(s));
             }
        }
        System.out.println("---------");
        //遍历2
        for (HashMap<String, String> hm:arr){
    
    
            Set<Map.Entry<String, String>> entries = hm.entrySet();
            for (Map.Entry<String, String> m:entries){
    
    
                System.out.println(m.getKey()+"  "+m.getValue());
            }
        }

    }
}

集合嵌套之HashMap嵌套ArrayList

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class qiantao2 {
    
    
    public static void main(String[] args) {
    
    
         HashMap<String, ArrayList<String>> hm = new HashMap<>();
         ArrayList<String> arr = new ArrayList<>();
         arr.add("刘备");
        arr.add("关羽");
        arr.add("张飞");
        hm.put("蜀国",arr);
        ArrayList<String> arr1 = new ArrayList<>();
        arr1.add("曹操");
        arr1.add("张辽");
        arr1.add("许褚");
        hm.put("魏国",arr1);
        ArrayList<String> arr2 = new ArrayList<>();
        arr2.add("孙权");
        arr2.add("孙策");
        arr2.add("周瑜");
        hm.put("吴国",arr2);


//        遍历1
         Set<String> key = hm.keySet();
          for (String s:key){
    
    
              System.out.println(s);
               ArrayList<String> lis = hm.get(s);
               for (String ss:lis){
    
    
                   System.out.println("   "+ss);
               }
          }
        System.out.println("-------------");
          //遍历2
         Set<Map.Entry<String, ArrayList<String>>> entries = hm.entrySet();
          for (Map.Entry<String, ArrayList<String>> mm:entries){
    
    
              System.out.println(mm.getKey());
               ArrayList<String> value = mm.getValue();
               for (String s:value){
    
    
                   System.out.println("   "+s);
               }
          }
    }
}

统计字符串中每个字符出现的次

import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;

public class Map {
    
    
    public static void main(String[] args) {
    
    
        Scanner sc=new Scanner(System.in);
        String s=sc.next();
        HashMap<Character, Integer> hm = new HashMap<>();
        for (int i=0;i<s.length();i++){
    
    
            char c=s.charAt(i);
            Integer num= hm.get(c);
            if(num==null){
    
    
              hm.put(c,1);
            }
            else{
    
    
                num++;
                hm.put(c,num);
            }
        }
        Set<Character> ss = hm.keySet();
        for (Character cc:ss){
    
    
            System.out.println(cc+" :"+hm.get(cc));
        }
    }
}


Collections概述和使用

在这里插入图片描述

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class collections01 {
    
    
    public static void main(String[] args) {
    
    
        //创建ArrayList集合对象
        ArrayList<student> arr = new ArrayList<>();
        //创建学生对象
        student s1 = new student(16, "tom");
        student s2 = new student(23, "jack");
        student s3 = new student(8, "mike");
        student s4 = new student(18, "mali");
        student s5 = new student(23, "jby");
        //把学生添加到集合
        arr.add(s1);
        arr.add(s2);
        arr.add(s3);
        arr.add(s4);
        arr.add(s5);
        //使用Collections对ArrayList集合排序        
        // sort•(List<T> list, Comparator<? super T> c) 
        Collections.sort(arr, new Comparator<student>() {
    
    
            @Override
            public int compare(student s1, student s2) {
    
    
                 int num=s2.getAge()-s1.getAge();//按年龄降序排列
                //int num=s1.getAge()-s2.getAge();//按年龄升序排列
                int num1=num==0?s1.getName().compareTo(s2.getName()):num;//如果年龄相同就按名字升序排序
                //int num1=num==0?s2.getName().compareTo(s2.getName()):num;//如果年龄相同按名字降序排列

                return  num1;

            }
        });
        //遍历集合
        for(student s:arr){
    
    
            System.out.println(s.getName()+" "+s.getAge());
        }
    }
}

模拟斗地主案例-普通版本
通过程序实现斗地主过程中的洗牌,发牌和看牌


import java.util.ArrayList;
import java.util.Collections;


public class collections_ddz {
    
    
    public static void main(String[] args) {
    
    
        //创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现
         ArrayList<String> arr = new ArrayList<>();
        //定义花色数组
         String [] colors={
    
    "♦","♣","♥","♠"};
        //定义点数数组
        String [] nums={
    
    "3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        for (int i=0;i<colors.length;i++){
    
    
            for(int j=0;j<nums.length;j++){
    
    
                arr.add((colors[i]+nums[j]));
            }
        }
        arr.add("小王");
        arr.add("大王");
        //创建3个打牌人的集合存储手中的牌和底牌集合
        ArrayList<String> p1 = new ArrayList<>();
        ArrayList<String> p2 = new ArrayList<>();
        ArrayList<String> p3 = new ArrayList<>();
        ArrayList<String> dp = new ArrayList<>();
        //洗牌,也就是把牌打撒,用Collections的shuffle()方法实现
        Collections.shuffle(arr);
        System.out.println(arr.size());
        //模拟发牌的过程
        for (int i=0;i<arr.size();i++){
    
    
            String poker=arr.get(i);
             if(i>=arr.size()-3){
    
    
                 dp.add(poker);
             }
             else if(i%3==0){
    
    
                 p1.add(poker);
             }
             else if(i%3==1){
    
    
                 p2.add(poker);
             }
             else if(i%3==2){
    
    
                 p3.add(poker);
             }
        }

        //看牌
        System.out.print("p1的牌是:");
        for (int i=0;i<p1.size();i++){
    
    
            System.out.print(p1.get(i)+" ");
        }
        System.out.println();
        System.out.print("p2的牌是:");
        for (int i=0;i<p2.size();i++){
    
    
            System.out.print(p2.get(i)+" ");
        }
        System.out.println();
        System.out.print("p3的牌是:");
        for (int i=0;i<p3.size();i++){
    
    
            System.out.print(p3.get(i)+" ");
        }
        System.out.println();
        System.out.print("底牌是:");
        for (int i=0;i<dp.size();i++){
    
    
            System.out.print(dp.get(i)+" ");
        }

    }

}

模拟斗地主案例-升级版本
通过程序实现斗地主过程中的洗牌,发牌和看牌。要求:对牌进行排序

import java.util.*;

public class shengjidoudizhu {
    
    

    public static void main(String[] args) {
    
    
        //创建HashMap,键是编号,值是牌 
        HashMap<Integer, String> hm = new HashMap<>();
        //创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现
        ArrayList<Integer> arr = new ArrayList<>();
        //定义花色数组
        String [] colors={
    
    "♦","♣","♥","♠"};
        //定义点数数组
        String [] nums={
    
    "3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        int index=0;
          //从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList里面存储编号
        for(int j=0;j<nums.length;j++){
    
    
        for (int i=0;i<colors.length;i++){
    
    

                hm.put(index,(colors[i]+nums[j]));
                arr.add(index);
                index++;
            }
        }

        hm.put(index,"小王");
        arr.add(index);
        index++;
        hm.put(index,"大王");
        arr.add(index);
       //洗牌(洗的是编号),用Collections的shuffle()方法实现
        Collections.shuffle(arr);
        TreeSet<Integer> p1 = new TreeSet<>();
        TreeSet<Integer> p2 = new TreeSet<>();
        TreeSet<Integer> p3 = new TreeSet<>();
        TreeSet<Integer> dp = new TreeSet<>();
        System.out.println(arr.size());


          //发牌(发的也是编号,为了保证编号是排序的,创建TreeSet集合接收)
        for (int i=0;i<arr.size();i++){
    
    
            int poker=arr.get(i);
            if(i>=arr.size()-3){
    
    
                dp.add(poker);
            }
            else if(i%3==0){
    
    
                p1.add(poker);
            }
            else if(i%3==1){
    
    
                p2.add(poker);
            }
            else if(i%3==2){
    
    
                p3.add(poker);
            }
        }
        //调用看牌方法
        lookpoker("p1",p1,hm);
        lookpoker("p2",p2,hm);
        lookpoker("p3",p3,hm);
        lookpoker("底牌",dp,hm);

    }
    //定义方法看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
    public static void lookpoker(String name,TreeSet<Integer> set,HashMap<Integer,String> hm){
    
    

        System.out.print(name+"的牌是:");
        for (Integer i:set){
    
    
            String s = hm.get(i);
            System.out.print(s+" ");
        }
        System.out.println();
    }
}

IO流

File类概述和构造方法

File类介绍 它是文件和目录路径名的抽象表示 
文件和目录是可以通过File封装成对象的 
对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。
它可以是存在的,也可以 是不存在的。将来是要通过具体的操作把这个路径的内
容转换为具体存在的

在这里插入图片描述

public class FileDemo01 {
    
        
public static void main(String[] args)
 {
    
            
//File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的 File 实例。        
File f1 = new File("E:\\itcast\\java.txt");        
System.out.println(f1);
 
//File(String parent, String child):从父路径名字符串和子路径名字符串创建新的 File实例。        
File f2 = new File("E:\\itcast","java.txt");        
System.out.println(f2);
 
//File(File parent, String child):从父抽象路径名和子路径名字符串创建新的 File 实例。        
File f3 = new File("E:\\itcast");        
File f4 = new File(f3,"java.txt");        
System.out.println(f4);   
    } 
}

在这里插入图片描述

import jdk.swing.interop.SwingInterOpUtils;

import java.io.File;
import java.io.IOException;

public class IO01 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //public boolean createNewFile()
        // 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件并返回true;
      //当文件已经存在时返回false
        //需求1:我要在D:\\iotest目录下创建一个文件java.txt
        File file = new File("D:\\iotest\\java.txt");
        System.out.println(file.createNewFile());//不存在则创建成功返回true;
        System.out.println(file.createNewFile());//存在则返回false;
        System.out.println("------------");
        //public boolean mkdir() 创建由此抽象路径名命名的目录

        //需求2:我要在D:\\iotest目录下创建一个目录JavaSE
         File file1 = new File("D:\\iotest\\javaSE");
        System.out.println(file1.mkdir());//不存在则创建成功返回true;
        System.out.println("------------");
        //需求3:我要在D:\\iotest目录下创建一个多级目录JavaWEB\\HTML
        //public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录

        File file2 = new File("D:\\iotest\\javaWEB\\HTML");
        System.out.println(file2.mkdirs());
        File file3 = new File("D:\\iotest\\javase.txt");
        System.out.println(file3.mkdir());//会返回true并创建javase.txt的文件夹
//        创建文件还是需要用createNewFile()不然会生成.txt的文件夹
    }
}

在这里插入图片描述

在这里插入图片描述

import java.io.File;
import java.io.IOException;
import java.sql.SQLOutput;

public class IO02 {
    
    

    public static void main(String[] args) throws IOException {
    
    
      File file = new File("D:\\iotest\\javaEE.txt");
//      file.createNewFile();
        //        public boolean isDirectory():测试此抽象路径名表示的File是否为目录
        //        public boolean isFile():测试此抽象路径名表示的File是否为文件
        //        public boolean exists():测试此抽象路径名表示的File是否存在
        System.out.println(file.isDirectory());//false
        System.out.println(file.isFile());//true
        System.out.println(file.exists());//true;
        System.out.println("--------------");
        //        public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串
        //        public String getPath():将此抽象路径名转换为路径名字符串
        //        public String getName():返回由此抽象路径名表示的文件或目录的名称
        System.out.println(file.getAbsoluteFile());
        System.out.println(file.getPath());
        System.out.println(file.getName());
        System.out.println("--------------");

        //        public String[] list():返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
        //        public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
       File file1 = new File("D:\\iotest");
         String[] list = file1.list();
         for (String s:list){
    
    
             System.out.println(s);
         }
        System.out.println("--------------");
         File[] files = file1.listFiles();
         for (File f:files){
    
    
             if(f.isFile()){
    
    
                 System.out.println(f);
                 System.out.println(f.getName());
             }
         }
    }



}

在这里插入图片描述

public class FileDemo03 {
    
        
public static void main(String[] args) throws IOException {
    
     //        File f1 = new File("E:\\itcast\\java.txt");        
//需求1:在当前模块目录下创建java.txt文件        
File f1 = new File("myFile\\java.txt");        System.out.println(f1.createNewFile());
 
        //需求2:删除当前模块目录下的java.txt文件          
        System.out.println(f1.delete());        
        System.out.println("--------");
 
        //需求3:在当前模块目录下创建itcast目录        
        File f2 = new File("myFile\\itcast"); //        
        System.out.println(f2.mkdir());
 
        //需求4:删除当前模块目录下的itcast目录        
        System.out.println(f2.delete());        
        System.out.println("--------");
 
        //需求5:在当前模块下创建一个目录itcast,然后在该目录下创建一个文件java.txt        
        File f3 = new File("myFile\\itcast"); //        
        System.out.println(f3.mkdir());        
        File f4 = new File("myFile\\itcast\\java.txt"); //        
        System.out.println(f4.createNewFile());
 
        //需求6:删除当前模块下的目录itcast        
        System.out.println(f4.delete());             
        System.out.println(f3.delete());    
 } 
}

绝对路径和相对路径的区别 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如:E:\itcast\java.txt
相对路径:必须使用取自其他路径名的信息进行解释。例如:myFile\java.txt

如果文件夹里面有文件则无法删除该文件

递归遍历目录

import java.io.File;

public class IO03 {
    
    

    public static void main(String[] args) {
    
    

         File srcfile = new File("D:\\iotest");
         getallpaths(srcfile);

    }
    public static void getallpaths(File srcfile){
    
    
        File[] files = srcfile.listFiles();
        if(files!=null){
    
    
            for (File f:files){
    
    
                if (f.isDirectory()){
    
    
                //递归调用
                    getallpaths(f);
                }
                else{
    
    
                    System.out.println(f.getAbsolutePath());
                }
            }
        }
    }
}

IO流概述和分类

IO流介绍
IO:输入/输出(Input/Output)
流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
IO流就是用来处理设备间数据传输问题的。常见的应用:文件复制;文件上传;文件下载

IO流的分类

   按照数据的流向 
        输入流:读数据
        输出流:写数据 
   按照数据类型来分 
       字节流 
       		字节输入流 
       		字节输出流 
       	字符流 
       		字符输入流 
       		字符输出流 

IO流的使用场景

如果操作的是纯文本文件,优先使用字符流
如果操作的是图片、视频、音频等二进制文件。优先使用字节流
如果不确定文件类型,优先使用字节流。字节流是万能的流

字节流抽象基类

InputStream:这个抽象类是表示字节输入流的所有类的超类
OutputStream:这个抽象类是表示字节输出流的所有类的超类

子类名特点:子类名称都是以其父类名作为子类名的后缀

字节输出流

字节输出流 FileOutputStream(String name):创建文件输出流以指定的名称写入文件

使用字节输出流写数据的步骤

创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输
出流对象指向文件) 
调用字节输出流对象的写数据方法
释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源) 

import java.io.FileOutputStream;
import java.io.IOException;

public class IO04 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //FileOutputStream(String name):创建文件输出流以指定的名称写入文件
         FileOutputStream fos = new FileOutputStream("D:\\iotest\\dyk.txt");
        /*            
        做了三件事情:                
        A:调用系统功能创建了文件              
         B:创建了字节输出流对象                
        C:让字节输出流对象指向创建好的文件        
        */

        fos.write(97);//将指定字节流写入文件输出流
         fos.close();//关闭字节流释放资源
    }
}

在这里插入图片描述


import java.io.FileOutputStream;
import java.io.IOException;

public class IO04 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //FileOutputStream(String name):创建文件输出流以指定的名称写入文件
         FileOutputStream fos = new FileOutputStream("D:\\iotest\\dyk.txt");
        /*            
        做了三件事情:                
        A:调用系统功能创建了文件              
         B:创建了字节输出流对象                
        C:让字节输出流对象指向创建好的文件        
        */
        //void write(int b) 将指定的字节写入此文件输出流 一次写一个字节数据
//          fos.write(97);
        //fos.write(97);//将指定字节流写入文件输出流
//          byte [] bys={97,98,99,100};

//         fos.write(bys);
        String str="abcdef";
        //fos.write(str.getBytes());//abcdef
        //void write(byte[] b, int off, int len)
        //将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一 次写一个字节数组的部分数据

         fos.write(str.getBytes(),0,4);//abcd
         fos.close();//关闭字节流释放资源
    }
}

字节流写数据的两个小问题

字节流写数据如何实现换行
windows:\r\n
linux:\n
mac:\r

字节流写数据如何实现追加写入

 public FileOutputStream(String name,boolean append) 

创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头

字节流写数据加异常处理

try{
    
        
可能出现异常的代码; 
}catch(异常类名 变量名){
    
        
异常的处理代码; 
}finally{
    
        
执行所有清除操作; 
}

finally特点 被finally控制的语句一定会执行,除非JVM退出

字节输入流

FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文 件系统中的路径名name命名

字节输入流读取数据的步骤

创建字节输入流对象 
调用字节输入流对象的读数据方法 
释放资源

字节流读数据(一次读一个字节数据)
字节输入流
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文 件系统中的路径名name命名

import com.sun.jdi.PathSearchingVirtualMachine;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class IO05 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建字节输入流对象        
        // FileInputStream(String name)
       FileInputStream fis = new FileInputStream("D:\\iotest\\dyk.txt");
       
        int by;
         /*            
        fis.read():读数据            
        by=fis.read():把读取到的数据赋值给by            
        by != -1:判断读取到的数据是否是-1        
        */
       while ((by=fis.read())!=-1){
    
    
           System.out.print((char)by);
       }
       fis.close();
    }
}

字节流复制文本文件



import java.io.FileInputStream;

import java.io.FileOutputStream;
import java.io.IOException;

public class IO05 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建字节输入流对象        
        // FileInputStream(String name)
        FileInputStream fis = new FileInputStream("D:\\iotest\\dyk.txt");
        FileOutputStream fos = new FileOutputStream("D:\\iotest\\dyk2.txt");

        int by;
         /*            
        fis.read():读数据            
        by=fis.read():把读取到的数据赋值给by            
        by != -1:判断读取到的数据是否是-1        
        */
        while ((by = fis.read()) != -1) {
    
    
            fos.write(by);
        }
        fis.close();
        fos.close();
    }
}

字节流读数据(一次读一个字节数组数据)

一次读一个字节数组的方法 public int read(byte[] b):从输入流读取最多b.length个字节的数据
返回的是读入缓冲区的总字节数,也就是实际的读取字节个数

import java.io.FileInputStream;
import java.io.IOException;

public class IO06 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建字节输入流对象
        FileInputStream fis = new FileInputStream("D:\\iotest\\dyk.txt");
         int len ;
         byte [] bys=new byte[1024];
         while ((len=fis.read(bys))!=-1){
    
    
             System.out.println(new String(bys,0,len));//1024及其整数倍 
         }

       fis.close();

    }
}

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class IO06 {
    
    
    public static void main(String[] args) throws IOException {
    
    
         FileOutputStream fos = new FileOutputStream("D:\\iotest\\dyk3.txt");
         FileInputStream fis=new FileInputStream("D:\\iotest\\dyk.txt");
         int len;
         byte[] bys=new byte[1024];
         while((len=fis.read(bys))!=-1){
    
    
             fos.write(bys,0,len);
         }
         fis.close();
         fos.close();
    }
}

字节缓冲流构造方法

lBufferOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写 入字节,而不必为写入的每个字节导致底层系统的调用
lBufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过 字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

import java.io.*;

public class IO07 {
    
    


    public static void main(String[] args) throws IOException {
    
    

         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\iotest\\dyk.txt"));

         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\iotest\\dyk4.txt"));

           int len;
           byte [] bys=new byte[1024];
           while ((len=bis.read(bys))!=-1){
    
    
                 bos.write(bys,0,len);
           }

          bos.close();
          bis.close();


    }
}

字符流

字符流的介绍
由于字节流操作中文不是特别的方便,所以Java就提供字符流
字符流 = 字节流 + 编码表
中文的字节存储方式
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接 成中文,如何识别是中文的呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

在这里插入图片描述

字符串中的编码解码问题

public class StringDemo {
    
        
public static void main(String[] args) throws UnsupportedEncodingException {
    
            
//定义一个字符串        
String s = "中国";
 
    //byte[] bys = s.getBytes(); //[-28, -72, -83, -27, -101, -67]        
    //byte[] bys = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67]        
    byte[] bys = s.getBytes("GBK"); //[-42, -48, -71, -6]        System.out.println(Arrays.toString(bys));
 
        //String ss = new String(bys);        
        //String ss = new String(bys,"UTF-8");        
        String ss = new String(bys,"GBK");              
        System.out.println(ss);    
   }
 }

字符流中和编码解码问题相关的两个类 InputStreamReader:是从字节流到字符流的桥梁
它读取字节,并使用指定的编码将其解码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集 OutputStreamWriter:是从字符流到字节流的桥梁
是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

import jdk.swing.interop.SwingInterOpUtils;

import java.io.*;

public class IO08 {
    
    

    public static void main(String[] args) throws IOException {
    
    
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("D:\\iotest\\osw.txt"),"GBK");
//        InputStreamReader isr=new InputStreamReader(new FileInputStream("D:\\iotest\\osw.txt"),"GBK");

       //void write(int c):写一个字符
        osw.write(97);
        //void writ(char[] cbuf):写入一个字符数组
        char [] chs={
    
    'a','b','c','d'};
        osw.write(chs);
       //void write(char[] cbuf, int off, int len):写入字符数组的一部分
        osw.write(chs,0,2);
        //void write(String str):写一个字符串
        osw.write("中国");
       //void write(String str, int off, int len):写一个字符串的一部分
        String sss="心好累感觉不会再爱了";

        osw.write(sss,0,3);
        //flush() 刷新流,之后还可以继续写数据
        osw.flush();
        //close() 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

        osw.close();

    }
}

在这里插入图片描述

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class IO09 {
    
    

    public static void main(String[] args) throws IOException {
    
    
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\iotest\\dyk4.txt"));

        int ch;
        //int read():一次读一个字符数据
        while ((ch = isr.read()) != -1) {
    
    
            System.out.print((char) ch);
        }

        //int read(char[] cbuf):一次读一个字符数组数据 
//        char[] chs=new char[1024];
//         int len;
//         while((len=isr.read(chs))!=-1){
    
    
//             System.out.println(new String(chs,0,len));
//         }
        isr.close();
    }
}

字符流复制Java文件

import java.io.*;

public class IO09 {
    
    

    public static void main(String[] args) throws IOException {
    
    
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\iotest\\dyk4.txt"));
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("D:\\iotest\\new.txt"));
//        int ch;
       //int read():一次读一个字符数据
//        while ((ch = isr.read()) != -1) {
    
    
//            osw.write(ch);
//        }

        //int read(char[] cbuf):一次读一个字符数组数据
        char[] chs=new char[1024];
         int len;
         while((len=isr.read(chs))!=-1){
    
    
           osw.write(chs,0,len);
         }
        isr.close();
        osw.close();
    }
}


FileReader​(String fileName) 创建一个新的 FileReader ,给定要读取的文件的名称路径  继承于InputStreamReader 
FileWriter​(String fileName) 构造一个给定文件名的FileWriter对象。  
FileWriter​(String fileName, boolean append) 构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。  
继承于OutputStreamWriter 

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class IO10 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileWriter fw=new FileWriter("D:\\iotest\\new1.txt");
        FileReader fr=new FileReader("D:\\iotest\\new.txt");
//        int ch;
//        while ((ch=fr.read())!=-1){
    
    
//            fw.write(ch);
//        }
        int len;
        char[] chs=new char[1024];
         while ((len=fr.read(chs))!=-1){
    
    
              fw.write(chs,0,len);
         }
        fw.close();
    }
}

字符缓冲流

字符缓冲流介绍 BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可 以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓 冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
在这里插入图片描述

import java.io.*;

public class IO11 {
    
    

    public static void main(String[] args) throws IOException {
    
    
        //BufferedWriter(Writer out)
        BufferedReader bf=new BufferedReader(new FileReader("D:\\iotest\\dyk4.txt"));
        //BufferedReader(Reader in)
        BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\iotest\\dyk5.txt"));
        //一次读取一个字符数据
        //        int ch;
//        while((ch=bf.read())!=-1){
    
    
//            System.out.print((char)ch);
//        }
        int len;
        char[] chs=new char[1024];

        while((len=bf.read(chs))!=-1){
    
    
//            System.out.println(new String(chs,0,len));
            bw.write(chs,0,len);
        }
        bf.close();
        bw.close();
    }

}

在这里插入图片描述

import java.io.*;

public class IO12 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //根据数据源创建字符缓冲输入流对象
      BufferedReader br = new BufferedReader(new FileReader("D:\\iotest\\dyk4.txt"));
        //根据目的地创建字符缓冲输出流对象
      BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\iotest\\new3.txt"));
        //读写数据,复制文件        
        // 使用字符缓冲流特有功能实现
      String line;
      while((line=br.readLine())!=null){
    
    
           bw.write(line);
           bw.newLine();
           bw.flush();
      }
      //释放资源
      br.close();
      bw.close();

    }
}

在这里插入图片描述
在这里插入图片描述

Properties集合

Properties作为Map集合的使用

Properties介绍
是一个Map体系的集合类
Properties可以保存到流中或从流中加载
属性列表中的每个键及其对应的值都是一个字符串
在这里插入图片描述

import java.util.Properties;
import java.util.Set;

public class properties01 {
    
    
    public static void main(String[] args) {
    
    
        Properties pro = new Properties();
        //普通方法
        pro.put("01", "张三");
        pro.put("02", "李四");
        pro.put("03", "王五");

        Set<Object> objects = pro.keySet();
        for (Object s : objects) {
    
    
            System.out.println((String) s + pro.get(s));
        }
        System.out.println("----------------");
        Properties pro1 = new Properties();
        //Object setProperty(String key, String value):设置集合的键和值,都是
        //String类型,底层调用Hashtable方法put

        pro1.setProperty("001", "张三");
        pro1.setProperty("002", "李四");
        pro1.setProperty("003", "王五");
        /*
        Object setProperty(String key, String value)
        {
        return put(key, value);
        }
        Object put(Object key, Object value)
        {
        return map.put(key, value);
        }
*/
        //String getProperty(String key):使用此属性列表中指定的键搜索属性

        //Set<String> stringPropertyNames():从该属性列表中返回一个不可修改的键集,其中
        //键及其对应的值是字符串

        Set<String> strings = pro1.stringPropertyNames();
        for (String s : strings) {
    
    
            System.out.println(s + " " + pro1.getProperty(s));
        }
    }
}

在这里插入图片描述

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class properties02 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //把集合中的数据保存到文件
         Properties pro = new Properties();
        pro.setProperty("001", "张三");
        pro.setProperty("002", "李四");
        pro.setProperty("003", "王五");
 FileWriter fw=new FileWriter("D:\\iotest\\123.txt");
        //void store(Writer writer, String comments)
        //将此属性列表(键和元素对)写入此 Properties表中,以适合使用
        //load(Reader)方法的格式写入输出字符流
        pro.store(fw,null);
        fw.close();

        //把文件中的数据加载到集合
//         Properties pro1=new Properties();
//        FileReader fr=new FileReader("D:\\iotest\\123.txt");
        //void load(Reader reader) 从输入字符流读取属性列表(键和元素对)
//        pro1.load(fr);
//        fr.close();
//        System.out.println(pro1);

    }
}

多线程
进程:是正在运行的程序
是系统进行资源分配和调用的独立单位
每一个进程都有它自己的内存空间和系统资源

线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序

在这里插入图片描述

public class xiancheng01 extends Thread{
    
    
    @Override
    public void run() {
    
    
        for(int i=0;i<100;i++){
    
    
            System.out.println(i);
        }
    }
}




public class xiancheng_test01 {
    
    
    public static void main(String[] args) {
    
    
        xiancheng01 xc1 = new xiancheng01();
        xiancheng01 xc2 = new xiancheng01();
         //xc1.run();
         //xc2.run();//直接调用,相当于普通方法的调用
        xc1.start();
        xc2.start();
    }
}

两个小问题
为什么要重写run()方法?
因为run()是用来封装被线程执行的代码
run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用
start():启动线程;然后由JVM调用此线程的run()方法

在这里插入图片描述
有两种方法可以实现线程命名
1.采用无参构造函数创建对象,然后利用setName方法
2,直接使用带参构造方法创建对象

public class MyThread extends Thread {
    
    
public MyThread() {
    
    }
public MyThread(String name) {
    
    
super(name);
}
@Override
public void run() {
    
    
for (int i = 0; i < 100; i++) {
    
    
System.out.println(getName()+":"+i);
}
}
}


public class MyThreadDemo {
    
    
public static void main(String[] args) {
    
    
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//void setName(String name):将此线程的名称更改为等于参数 name
my1.setName("高铁");
my2.setName("飞机");
//Thread(String name)
MyThread my1 = new MyThread("高铁");
MyThread my2 = new MyThread("飞机");
my1.start();
my2.start();
//static Thread currentThread() 返回对当前正在执行的线程对象的引用
//此方法是一个静态方法,直接用类名调用
System.out.println(Thread.currentThread().getName());
}
}

线程调度
两种调度方式
分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一
个,优先级高的线程获取的 CPU 时间片相对多一些
Java使用的是抢占式调度模型
随机性
假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也
就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一
定的

在这里插入图片描述

在这里插入图片描述

sleep演示:

static void sleep(long millis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数
public class ThreadSleep extends Thread {
    
    
@Override
public void run() {
    
    
for (int i = 0; i < 100; i++) {
    
    
System.out.println(getName() + ":" + i);
try {
    
    
Thread.sleep(1000);
} catch (InterruptedException e) {
    
    
e.printStackTrace();
}
}
}
}
public class ThreadSleepDemo {
    
    
public static void main(String[] args) {
    
    
ThreadSleep ts1 = new ThreadSleep();
ThreadSleep ts2 = new ThreadSleep();
ThreadSleep ts3 = new ThreadSleep();
ts1.setName("曹操");
ts2.setName("刘备");
ts3.setName("孙权");
ts1.start();
ts2.start();
ts3.start();
}
}
Join演示:
public class ThreadJoin extends Thread {
    
    
@Override
public void run() {
    
    
for (int i = 0; i < 100; i++) {
    
    
System.out.println(getName() + ":" + i);
}
}
}



//void join() 等待这个线程死亡其他的线程才能执行
public class ThreadJoinDemo {
    
    
public static void main(String[] args) {
    
    
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.setName("康熙");
tj2.setName("四阿哥");
tj3.setName("八阿哥");
tj1.start();
try {
    
    
tj1.join();
} catch (InterruptedException e) {
    
    
e.printStackTrace();
}
tj2.start();
tj3.start();
}
}


//void setDaemon(boolean on)
//将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
Daemon演示:
public class ThreadDaemon extends Thread {
    
    
@Override
public void run() {
    
    
for (int i = 0; i < 100; i++) {
    
    
System.out.println(getName() + ":" + i);

public class ThreadDaemonDemo {
    
    
public static void main(String[] args) {
    
    
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
td1.setName("关羽");
td2.setName("张飞");
//设置主线程为刘备
Thread.currentThread().setName("刘备");
//设置守护线程
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
for(int i=0; i<10; i++) {
    
    
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}

在这里插入图片描述
在这里插入图片描述

public class myrunnable implements  Runnable{
    
    

    @Override
    public void run() {
    
    
        for (int i=0;i<100;i++){
    
    
            //因为没有继承thread所以没法直接使用getName方法
            System.out.println(Thread.currentThread().getName()+" :"+i);
        }
    }
}

public class myrunnabletest {
    
    
    public static void main(String[] args) {
    
    
         myrunnable my = new myrunnable();
        //Thread(Runnable target) 分配一个新的Thread对象
//         Thread th1=new Thread(my);
//         Thread th2=new Thread(my);
//         th1.setName("张三");
//         th2.setName("李四");

        //Thread(Runnable target, String name) 分配一个新的Thread对象
        Thread th1=new Thread(my,"张三");
        Thread th2=new Thread(my,"李四");
         th1.start();
         th2.start();
    }
}

多线程的实现方案有两种
继承Thread类
实现Runnable接口
相比继承Thread类,实现Runnable接口的好处
避免了Java单继承的局限性
适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现
了面向对象的设计思想

网络编程
IP地址
要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接收数
据的计算机和识别发送的计算机,而IP地址就是这个标识号。也就是设备的标识
端口
网络的通信,本质上是两个应用程序的通信。每台计算机都有很多的应用程序,那么在网络通信时,如何区
分这些应用程序呢?如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序
了。也就是应用程序的标识
协议
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定
的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则
被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守
才能完成数据交换。常见的协议有UDP协议和TCP协议

DOS常用命令:
ipconfig:查看本机IP地址
ping IP地址:检查网络是否连通
特殊IP地址:
127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用

在这里插入图片描述

import java.net.InetAddress;
import java.net.UnknownHostException;

public class l1 {
    
    
    public static void main(String[] args) throws UnknownHostException {
    
    
       InetAddress address = InetAddress.getByName("127.0.0.1");
        //public String getHostAddress():返回文本显示中的IP地址字符串
         String hostAddress = address.getHostAddress();
        //public String getHostName():获取此IP地址的主机名
         String hostName = address.getHostName();

        System.out.println(hostAddress+"   "+hostName);
    }
}

端口和协议

端口
设备上应用程序的唯一标识
端口号
用两个字节表示的整数,它的取值范围是0-65535。其中,0~1023之间的端口号用于一些知名的网络服
务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会
导致当前程序启动失败
协议
计算机网络中,连接和通信的规则被称为网络通信协议

UDP协议
用户数据报协议(User Datagram Protocol)
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台
计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在
收到数据时,也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输

例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太
大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在
传输重要数据时不建议使用UDP协议

TCP协议
传输控制协议 (Transmission Control Protocol)
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数
据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由
客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
第一次握手,客户端向服务器端发出连接请求,等待服务器确认
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
第三次握手,客户端再次向服务器端发送确认信息,确认连接
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,
TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等

UDP发送数据
在这里插入图片描述
在这里插入图片描述
发送数据的步骤

创建发送端的Socket对象(DatagramSocket)
创建数据,并把数据打包
调用DatagramSocket对象的方法发送数据
关闭发送端

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UDPsendTest {
    
    
    public static void main(String[] args) throws IOException {
    
    
        /*
      UDP发送数据:
      数据来自于键盘录入,直到输入的数据是886,发送数据结束
      */
        //创建发送端的Socket对象(DatagramSocket)
        // DatagramSocket() 构造数据报套接字并将其绑定到本地主机上的任何可用端口
        DatagramSocket ds = new DatagramSocket();
        Scanner sc = new Scanner(System.in);
        try {
    
    
            while (true) {
    
    
                String message = sc.nextLine();
                //输入的数据是886,发送数据结束
                if ("886".equals(message)) {
    
    
                    break;
                }
                byte[] bys = message.getBytes();
                //创建数据,并把数据打包
                //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
                //构造一个数据包,发送长度为 length的数据包到指定主机上的指定端口号。
                DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("127.0.0.1"), 10086);
                //调用DatagramSocket对象的方法发送数据
                //void send(DatagramPacket p) 从此套接字发送数据报包
                ds.send(dp);
            }
        } finally {
    
    
            System.out.println("发送结束");
            //关闭发送端
            //void close() 关闭此数据报套接字
            ds.close();
        }


    }
}


在这里插入图片描述
接收数据的步骤
创建接收端的Socket对象(DatagramSocket)
创建一个数据包,用于接收数据
调用DatagramSocket对象的方法接收数据
解析数据包,并把数据在控制台显示
关闭接收端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;


public class UDPrecieveTset {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建接收端的Socket对象(DatagramSocket)
         DatagramSocket ds = new DatagramSocket(10086);
       /*
     UDP接收数据:
     因为接收端不知道发送端什么时候停止发送,故采用死循环接收
      */
        while (true){
    
    

            byte[] bys = new byte[1024];
            //创建一个数据包,用于接收数据
            DatagramPacket dp = new DatagramPacket(bys, bys.length);
            //调用DatagramSocket对象的方法接收数据

            ds.receive(dp);
            System.out.println("接收的数据是:"+new String(dp.getData(),0,dp.getLength()));
        }

    }
}

Java中的TCP通信
Java对基于TCP协议的的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过
Socket产生IO流来进行网络通信。
Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Lambda表达式
启动一个线程,在控制台输出一句话:多线程程序启动了,三种方式

public class lambda01 implements Runnable{
    
    
    @Override
    public void run() {
    
    
        System.out.println("多线程启动了1");
    }

    public static void main(String[] args) {
    
    
        //方法一传实现了runable的接口的对象
          lambda01 lambda01 = new lambda01();
        Thread thread = new Thread(lambda01);
        thread.start();
        //方法二采用匿名内部类
        Thread thread1 = new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println("多线程启动了2");
            }
        });
        thread1.start();

         //方法三采用lambda表达式
         Thread thread2=new Thread(()->{
    
    
             System.out.println("多线程启动了3");
         });
         thread2.start();
    }
}

格式:
(形式参数) -> {代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
组成Lambda表达式的三要素:
形式参数,箭头,代码块

类加载
类加载的描述
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始
化这三个步骤来对类进行初始化。如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把
这三个步骤统称为类加载或者类初始化
类的加载
就是指将class文件读入内存,并为之创建一个 java.lang.Class 对象
任何类被使用时,系统都会为之建立一个 java.lang.Class 对象
类的连接
验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
准备阶段:负责为类的类变量分配内存,并设置默认初始化值
解析阶段:将类的二进制数据中的符号引用替换为直接引用
类的初始化
在该阶段,主要就是对类变量进行初始化
类的初始化步骤
假如类还未被加载和连接,则程序先加载并连接该类
假如该类的直接父类还未被初始化,则先初始化其直接父类
假如类中有初始化语句,则系统依次执行这些初始化语句
注意:在执行第2个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3
类的初始化时机
创建类的实例
调用类的类方法
访问类或者接口的类变量,或者为该类变量赋值
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类

类加载器
负责将.class文件加载到内存中,并为之生成对应的 java.lang.Class 对象。虽然我们不用过分关心类加载机
制,但是了解这个机制我们就能更好的理解程序的运行!

JVM的类加载机制
全盘负责:就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载
器负责载入,除非显示使用另外一个类加载器来载入
父类委托:就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器
无法加载该类时才尝试从自己的类路径中加载该类
缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜
索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成
Class对象,存储到缓存区

Java中的内置类加载器
Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null ,并且没有父null
Platform class loader:平台类加载器可以看到所有平台类 ,平台类包括由平台类加载器或其祖先定义的Java
SE平台API,其实现类和JDK特定的运行时类
System class loader:它也被称为应用程序类加载器 ,与平台类加载器不同。 系统类加载器通常用于定义应
用程序类路径,模块路径和JDK特定工具上的类
类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap

在这里插入图片描述

public class ClassLoaderDemo {
    
    
public static void main(String[] args) {
    
    
//static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c); //AppClassLoader
//ClassLoader getParent():返回父类加载器进行委派
ClassLoader c2 = c.getParent();
System.out.println(c2); //PlatformClassLoader
ClassLoader c3 = c2.getParent();
System.out.println(c3); //null
}
}

反射的概述
获取Class类对象的三种方式
类名.class属性
对象名.getClass()方法

public class fs01 {
    
    

    public static void main(String[] args) throws ClassNotFoundException {
    
    
        //使用类的Class属性来获取该类的Class对象
         Class<student> studentClass = student.class;
        System.out.println(studentClass);

        Class<student> studentClass2 = student.class;
        System.out.println(studentClass2==studentClass);
        System.out.println(studentClass2);

        //调用对象的getclass()方法,返回该对象所属类对应的Class对象
         student student = new student();
         Class<? extends student> aClass = student.getClass();
        System.out.println(studentClass==aClass);

        //使用Class类中的静态方法forname(string classname)
         Class<?> student1 = Class.forName("student");
        System.out.println(student1==studentClass);
    }
}

在这里插入图片描述

在这里插入图片描述

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class reflect02 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
        //获取Class对象
        Class<?> reflect = Class.forName("student");
        //Constructor<?>[] getConstructors() 返回一个包含 Constructor对象的数组,
        //Constructor对象反映了由该 Class对象表示的类的所有公共构造函数
     // Constructor<?>[] cons = c.getConstructors();
     //Constructor<?>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类
        //声明的所有构造函数的 Constructor对象的数组
         Constructor<?>[] cons= reflect.getDeclaredConstructors();
         for (Constructor c:cons){
    
    
             System.out.println(c);
         }
         //运行结果
         //public student()
        //public student(int,int,java.lang.String,java.lang.String)

        //Constructor<T> getConstructor(Class<?>... parameterTypes)
        //返回一个Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数
        //Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        //返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数
        //参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
         Constructor<?> constructor = reflect.getConstructor();
        //Constructor提供了一个类的单个构造函数的信息和访问权限
//T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,
        //使用指定的初始化参数来创建和初始化构造函数的声明类的新实例

        Object o = constructor.newInstance();
        System.out.println(o);


         Constructor<?> constructor1 = reflect.getConstructor(int.class, int.class, String.class, String.class);
         Object o1 = constructor1.newInstance(12, 1, "张三", "男");
        System.out.println(o1);

         Constructor<?> constructor2 = reflect.getDeclaredConstructor(String.class);
        //暴力反射 可以使用私有的方法
        //public void setAccessible(boolean flag):值为true,取消访问检查

        constructor2.setAccessible(true);
        Object o2 = constructor2.newInstance("李四");
        System.out.println(o2);
    }
}

在这里插入图片描述
在这里插入图片描述

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class reflect03 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
        //获取Class对象

        Class<?> stuclass = Class.forName("student");
         Field[] declaredFields = stuclass.getDeclaredFields();
        //Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段
        //Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段
        for (Field f:declaredFields){
    
    
            System.out.println(f);
        }

        //遍历结果
        //private int student.age
        //private int student.id
        //private java.lang.String student.name
        //private java.lang.String student.sex


        //Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段
        //Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该Class对象表示的类或接口的指定声明字段
        //获取无参构造方法创建对象
        Constructor<?> con = stuclass.getDeclaredConstructor();
       Object obj = con.newInstance();
        Field agefield = stuclass.getDeclaredField("age");
        agefield.setAccessible(true);
        agefield.set(obj,12);


         Field idfield = stuclass.getDeclaredField("id");
         idfield.setAccessible(true);
         idfield.set(obj,1);

         Field namefield = stuclass.getDeclaredField("name");
         namefield.setAccessible(true);
        namefield.set(obj,"张三");

        System.out.println(obj);

    }
}

在这里插入图片描述
在这里插入图片描述

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class reflect04 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
//        public void method1(){
    
    
//            System.out.println("公共无参成员方法没有返回值");
//        }
//        public  void method2(String s){
    
    
//            System.out.println("公共有参成员方法没有返回值参数是"+s);
//        }
//        public  String method03(String s,int i){
    
    
//            //System.out.println("公共有参成员方法有返回值");
//            return s+","+i;
//        }
//        private  void method4(){
    
    
//            System.out.println("私有无参成员方法没有返回值");
//        }

         Class<?> studentclass = Class.forName("student");

        //Method[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类
//Method[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法
//         Method[] methods = studentclass.getMethods();
         Method[] methods = studentclass.getDeclaredMethods();
        for (Method m:methods){
    
    
            System.out.println(m);
        }




//Method getMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法
//Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象
         Constructor<?> con = studentclass.getConstructor();
         Object obj = con.newInstance();

        Method m1= studentclass.getDeclaredMethod("method1");
        m1.invoke(obj);

        Method m2 = studentclass.getMethod("method2", String.class);
        m2.invoke(obj,"\tpublic  void method2(String s)");

         Method m3 = studentclass.getMethod("method03", String.class, int.class);
         Object s = m3.invoke(obj, "公共有参成员方法有返回值", 123);
        System.out.println(s);

        //因为method4是私有的所以需要暴力反射
         Method m4 = studentclass.getDeclaredMethod("method4");
         m4.setAccessible(true);
         m4.invoke(obj);

    }
}

反射练习之越过泛型检查

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class reflect05 {
    
    
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    
    
        //通过反射技术,向一个泛型为Integer的集合中添加一些字符串数据
        ArrayList<Integer> list = new ArrayList<>();

         Class<? extends ArrayList> c = list.getClass();
         Method add = c.getMethod("add",Object.class);
         add.invoke(list,"hello");
        add.invoke(list,"world");
        add.invoke(list,"java");
        System.out.println(list);
    }
}

运行配置文件中指定类的指定方法
在src下面建一个.properties的配置文件

classname=student
classmethod=method1
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class reflect06 {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
         Properties properties = new Properties();
         InputStream is= reflect06.class.getResourceAsStream("db.properties");
         properties.load(is);

         Class<?> c = Class.forName(properties.getProperty("classname"));
         Constructor<?> con = c.getDeclaredConstructor();
        Object obj = con.newInstance();

         Method method = c.getDeclaredMethod(properties.getProperty("classmethod"));
         method.setAccessible(true);
        method.invoke(obj);


    }
}

猜你喜欢

转载自blog.csdn.net/qq_44866153/article/details/105128692
今日推荐