全 | java基础笔记

JAVA

2022补充知识

1.定义栈

​ Stack<栈中的数据类型> name=new Stack<>();

import java.util.Stack; //存在于Java.util包中,需要引入
Stack<int> sta=new Stack<>();
2.栈中常用方法
sta.push(3); //向栈中打入数据3
sta.pop();   //弹出一个数据
sta.isEmpty(); //返回一个bool值 表示栈是否为空
HashMap

本质:存储Key --value键值对的对象

注意 HashMap和HashSet都是无序的,不会记录插入顺序

比起数组,链表需要按序查找的局限,哈希表具有索引直取的优良特性

import java.util.HashMap; //存在于Java.util包中,需要引入
//HashMap 中的元素实际上是对象,一些常见的基本类型可以使用它的包装类。
HashMap<Integer,String>Sites=new HashMap<Integer,String>();
//put添加键值对
Sites.put(1,"feel");
Sites.put(2,"hello");
System.out.println(Sites);//{1=feel,2=hello}

//键与值也可以取其他类型:
HashMap<String,String> Sites=new HashMap<String,String>();
Sites.put("yy","hello");
Sites.put("xx","helllll");

//通过key操作数据
//get查询元素
System.out.println(Sites.get("yy")) ;//hello
//remove 删除元素
Sites.remove("yy");

//计算哈希表大小
xxxxx(Sites.size());//2
//获取哈希表中所有value(返回一个数组)
Sites.values()
//获取哈希表中所有的key(返回一个数组)
Sites.keySet()
// 	检查 hashMap 中是否存在指定的 key 对应的映射关系  return bool
Sites.containsKey(xx)
//检查 hashMap 中是否存在指定的 value 对应的映射关系。
Sites.containsValue(xx)    
HashSet(哈希集)

本质:一个没有重复元素的集合(并不是数组)

import java.util.HashSet;

HashSet<String> sites=new HashSet<String>();
sites.add("a");
sites.add("b");
sites.add("a")//重复的元素将不再被添加
System.out.println(sites); //[a,b]

//判段相关元素是否存在
xxx(sites.contains("a"));  //true
//删除元素
sites.move("a");
//计算元素个数
sites.size();
//也可以使用增强for循环迭代
ArrayList类

本质:数组队列,没有固定的大小限制,可以添加或删除元素

快速上手
import java.util.ArrayList; //引入
ArrayList<E> xxx=new ArrayList<>(); 

ArrayList中的元素都是对象,所以E只能为引用数据类型,当然目前我对这些名词也不是非常了解,总之需要用包装类

import java.util.Comparator;
ArrayList<String>sites=new ArrayList<String>();
//注意索引从0开始
//添加元素
sites.add("cirs");
sites.add("william");
//访问元素
xxx(sites.get(1)) ;  //william
//修改元素
sites.set(1,"jackson"); //将William更改为jackson
//删除元素
sites.remove(1);
//计算大小
sites.size();
//排序 sort()方法
sites.sort(xxx); //参数为顺序方式
// 在此,Java Comparator 接口的 naturalOrder() 方法指定元素以自然顺序(升序)排序Comparator 接口还提供了对元素进行降序排列的方法:使用前记得引入
sites.sort(Comparator.naturalOrder()); 
sites.sort(Comparator.reverseOrder());
//其他方式实现升序
sites.sort((a,b)->a-b);
数组方法
增强for循环
int[] nums={1,2,3};
//遍历数组值    该方法通过定义一个变量(如num)装载当前遍历到的数组值
for(int num:nums){
    System.out.println("当前遍历到的数字是"+num);
}
//keySet() 方法可以与 for-each 循环一起使用,用来遍历迭代 HashMap 中的所有键。4
for(int key:sites.keySet()){
    System.out.println("key:"+key);
}

2021前置知识

数组
1.初始化方式
//静态:立即赋值
int[] arr;//声明
arr=new int[]{1,2,3};  //先声明再初始化(赋值)
int[] arr=new int[]{1,2,3};//声明时赋值(支持简写)
/*简写*/ int[] arr={1,2,3}  
//动态:系统分配初始值
int[] arr=new int[3];  //数组长度为3 默认值为0

关于 int[] 我的理解:

类似js 中,可以把int[]看成数组字面量,和Array类似,是一种数组标识,故可以理解为何静态初始化时 [] 中不能加数字。

上述的Array初始化时都需要指定固定的大小,使用ArrayList类则可以突破这一限制,可以理解为一个数组队列,可以任意添加,删除,寻找,甚至排序元素(见上方)

2.内存原理

数组变量(数组名)存储数组对象的首地址,被储存在栈中,初始化后,数组对象被存储在堆中连续的存储空间。一旦初始化完成,内存分配即结束,后续再无法改变数组的长度。

3.二维数组
//静态初始化
int[][] arr=new int[][]{
    {1},
    {1,2,3},
    {4,5}
};//类似的也可以简写、也可以先声明再写
//动态
int[][] arr=new int[3][4]; //动态初始化3*4列的数组
//ps:对于一个二维数组,二维数组的长度就是其行的数目,即3
4.特殊的二维数组—锯齿形(三角状)
//动态初始化锯齿行数组
int[][] arr=new int[5][];//只指定第一个下标
arr[0]=new int[5];
arr[1]=new int[4];
arr[2]=new int[3];
arr[3]=new int[2];
arr[4]=new int[1];
5.补充:打印数组的方式
import java.util.Arrays;

int[] arr= {1,2,3};
System.out.println(Arrays.toString(arr));  //打印数组  [1,2,3]
//ps:Arrays.toString()方法内核是创建了一个StringBuilder,依次添加‘[’ '1'  '2'  '3'  ],最后用toString转换为String类型,返回一个字符串
方法

补充:注意:java中,函数的形参必须是完整的参数类型,加参数名,即 int num1, 不能只写参数类型:int

1.定义

理解角度:就是函数,部分代码封装起来,以供程序反复调用。

//定义的语法格式
/*例子*/ public static int hanshuming(int num1,int num2){
    XXXXX
}//修饰符 返回值类型 方法名称 (形参列表)
2.方法调用的内存原理

每调用一个方法,jvm创建一个新的栈帧,用于保存传入形参和局部变量的值,该方法操作的都是该栈帧中的值。待调用结束,释放对应栈帧。

可见:实参和形参的存储单元不同

3.方法重载

重载概念:方法名称相同,形参列表不同的方法(即参数类型,顺序,数目,任意一个不同即可),对返回值不做要求。在调用方法时,编译器会寻找最准确的方法进行调用。

4.数组的引用传递

向方法传递数组时,传递的是数组名,相当于把地址值赋给了栈中的另一个变量pa, pa指向堆中的数组对象,可以对其进行操纵,对栈中的局部变量newarr进行初始化,newarr的数组对象被存在堆区,方法执行完毕,局部变量pa、newarr都将被释放,但newarr值被传递出去,给了copy,copy指向那片堆区

我认为ps:方法调用完毕,释放的是栈中的变量,即栈中保存的地址,而其指向的数组对象在堆区。故不会消失,copy得到地址后,还可以指向

int[] array={1,2,3};
int[] copy=rev(array);
public static void rev(int[] pa){
    int[] newarr=new int[pa.length];
    /*复制值的过程 xxxxxxx*/
    return newarr;
}
面向对象
1.类与对象

类是封装对象行为和属性的载体,对象是类抽象出来的实例。

类的特性:封装(隐藏类的细节,增加安全性),继承,多态

//类的定义
class Person{       //类名大写!!
    String name;    //声明属性
    int age; 
    public void say(){        //定义方法
        System.out.println("haha");
    }
}
//对象的创建
Person wang=new Person();//对象名是一个引用变量,类似数组变量。利用new实例化一个对象后,将返回对象的引用 ,并赋给wang,wang存在于栈中,指向堆中的对象。当某对象不再被任何变量引用时(即没有变量存其地址),该对象变为垃圾,等待回收。
//new创建对象时,会为每个对象开辟独立的堆空间,保存成员变量的值,且会*****自动为成员变量赋默认值。!!!****
2.访问控制符

控制使用权限的关键字,在类、成员变量、方法前均可以添加。

有:public 、 private 、 protected 、 默认(即不加)

  • public :均可以访问,对于其他包类的访问,需要导入相关Public类所在的包
  • protected:同一包中其他包的子类均可访问,其他包中的非子类不能访问
  • 默认:包访问性,同一包才能访问,与是否是子类无关
  • private:最高级别保护,只有在当前类中才能访问
3.构造方法
//new 关键字创建对象时被调用,用于为类中属性初始化
class Person{
    public Person(){                  //方法名与类名相同 且 没有返回值类型!!!
        System.out.println("构造方法自动被调用");
    }
}
//如果在类中未定义任何构造方法,系统自动默认提供一个。若已经有,则不再提供
//常见错误:你自己定义了一个有参构造,下面又 Person p=new Person();会因找不到相应的无参构造而报错。
//构造方法是可以重载的,根据需要设置参数。为避免上述错误,在定义类的构造方法时,应预先定义一个无参的构造方法。
4.this 关键字

this就是当前调用对象本身。一般在类中使用,通过this可以调用类中的属性、方法。

特别的,在构造函数中 通过 this(形参列表) 可以调用相应形参列表的其他构造函数!但只能掉一次,且位于首行

5.垃圾回收

使用new 创建数组、对象等引用类型,都将在堆中为其分配一块内存保存对象,当某对象不再被任何变量引用时(即没有变量存其地址),该对象变为垃圾,等待回收。JVM会自动清理被占用的 内存,无需显示释放(与C不同)

6.static关键字

static表示静态的,用于修饰成员变量,成员方法,以及代码块。不能修饰成员方法中的局部变量!!!

//静态变量
//static修饰的成员变量称为静态变量或类变量,被类的所有对象共享,为类所有,故可以用类名直接访问,无需创建对象
class Person{
    String name;
    static int age;
}  
public class TestStatic{
    public  static void main(String[] args){
        System.out.println(Person.age);//该内存中只有一份age,不管创建多少个对象,age都是同一个
        Person p=new Person();
        System.out.println(p.name);//未使用static 修饰的成员变量,称为实例变量,未具体对象所有,必须通过引用变量调用
    }
}
//静态方法
//为类所有,故可以用类名直接访问,无需创建对象 ,但静态方法只能使用静态成员不能使用实例成员
//由于main方法固定声明为静态方法,所以想要在main方法中使用的方法必须声明为静态
class Person{
    String name;
    static int age;
    public static void say(){
        System.out.println(age); //正确
        System.out.println(name); //错误  实例变量必须在对象开辟内存后才能使用
    }
}
7.内部类

内部类与外部类,经编译后生成的两个类是独立的;

内部类是外部类的成员,内部类可以直接访问外部类的所有成员,而外部类想访问内部类,则需要创建内部类对象。

内部类可以为静态,可以用protected、private修饰,而外部类,只能用public 和默认显示

//成员内部类
//外部类外创建内部类对象语法
class Other{
    private String name="waibu";
    private int age;
    class Inner{   //定义内部类成员
        private String name="neibu";
        public void say(){
            System.out.println(Other.this.name); //外部类名.this  表示外部类对象  waibu
            System.out.println(this.name);//neibu
            System.out.println(age);  //不重名的情况下可以直接访问
        }
    }
}
public class TestInner{
    public  static void main(String[] args){
        //在外部创建一个内部类对象
        Other.Inner obj=new Other().new Inner();
        obj.say();//waibu  neibu 0
    }
}
//静态内部类
class Other{
    private static String name="waibu";
    private int age;
    static class Inner{   //定义静态内部类成员
        private static String name="neibu";
        public void say(){
            System.out.println(Other.name); //  表示外部类静态对象  waibu
            System.out.println(name);//neibu
            System.out.println(age);  //不重名的情况下可以直接访问
        }
    }
}
public class TestInner{
    public  static void main(String[] args){
        String str=Other.Inner.name;  //访问静态内部类的静态成员 
        //在外部创建一个静态内部类对象
        Other.Inner obj=new Other.Inner(); //因为静态成员可以直接用类名调用,无需创建对象
        obj.say();//waibu  neibu 0
    }
}
//静态成员的访问无需创建对象,直接用类名调用,但实例对象就要创建,对象调用

//方法内部类
//即在成员方法中定义的类,与局部变量类似,作用域仅在当前方法中,只能在方法中对其进行实例化。
面向对象(下)
1.继承

继承:即在已有类型上定义新的类,新的类继承原有类的属性与方法,并扩展新的功能。已有类称为父类/基类,新的类称为子类/派生类。

//继承的语法格式
class parent{
    String name;
    double property;
    protected void say(){
        System.out.println("BABA");
    }
}
class son extends parent{
    int age;          //增加属性,扩展父类功能
    public void say(){
        System.out.println("haizi");  //重写父类方法
        super.say();  //"BABA"
    }
}

2.重写父类方法的理解
  • 重写父类方法:即重新定义父类的成员方法,被子类重写的方法不能比原父类方法的权限更严格。

  • 重写父类方法只能改变修饰符,类名,返回值,参数,都不能变。

    注意:参数不能变仅指参数类型/个数不能变,但形参的参数名可以任意指定

  • 方法重写与方法重载的区别:方法重载是在一个类中,而重写是在不同类(父子类)

3.super关键字的使用

使用1:当父类方法被重写,子类对象将不能访问原方法,如果需要访问被重写的原方法,可以用super实现。

使用二:在实例化子类对象时,首先会调用父类的构造方法,在调用子类本身。

//1.利用super显式调用
class Parent{
    String name;
    public Parent(){
        System.out.println("隐式调用默认调用无参的构造函数");
}
    public Parent(String name){
        System.out.println(name);
    }
}
class Son extends Parent{
    int age;          //增加属性,扩展父类功能
    public Son(){
        super("haizi gei baba de ");  //调用父类的有参构造
    }
}
//2.隐式调用
class Parent{
    String name;
    public Parent(){
        System.out.println("实例化对象时,先默认调用无参的构造函数");
}
    public Parent(String name){
        System.out.println(name);
    }
}
class Son extends Parent{
    int age;          //增加属性,扩展父类功能
    public Son(){
        System.out.println("然后再输出自己的构造函数内容");
    }
}
4.final关键字的使用
  • final关键字修饰类

final关键字修饰的类为最终类,不能再被其他类继承

  • final关键字修饰方法

final关键字修饰的方法,不能再被其子类重写,故称之为最终方法。

  • final关键字修饰变量

    final关键字修饰的变量,称为常量,只能初始化(赋值)一次

    //例1:final修饰局部变量
    final int age=18;  //age不能再被修改
    //2.final修饰成员变量
    //java 虚拟机不会为final修饰的变量默认初始化,所以这里age未被初始化,不能使用!
    //故被final修饰的成员变量,必须在声明时初始化:1.构造函数中赋值2.直接赋值
    class Parent{
    	final int age;
        public void say(){
            system.out.println(age);  //18
        }
        //利用构造函数赋值
        public Parent(int age){
            this.age=age;
    }
    }
    public class TestInner{
        public  static void main(String[] args){
            Parent p=new Parent(18);
        }} 
    
5.抽象类与接口
1.抽象类(abstract关键字)
  • 抽象类、抽象方法:用abstract关键字修饰的类、方法。

  • 抽象方法:只有方法的声明,没有方法体的方法称为抽象方法。该方法的方法体由子类根据实际需求实现。

    只要含一个抽象方法的类一定是抽象类。:抽象类也可以不含任何抽象方法。此时当作正常类用就行,只是不能被实例化。

  • 抽象类不能被实例化(new),只能通过子类继承才实现,因为可能包含抽象方法,而抽象方法不能被调用。

    由此得:抽象方法不能被final、static、private关键字修饰,(对于static:因为其修饰的方法能直接通过类名调用,而抽象方法不能被调用)

    //定义一个抽象类
    abstract class Parent{
        //声明两个抽象方法
        public abstract void say(String s);
        public abstract void work();
    }
    class Son extends Parent{
        //实现抽象方法
        public void say(String s){
            System.out.println(s);   //实现抽象方法时,参数列表要相同
        }
        //抽象类的子类必须实现父类所有的抽象方法,否则子类仍继承有抽象方法,故子类也必须声明为抽象类
        public void work(){
            System.out.println("work is happy");
        }
    }
    
2.接口(interface关键字)
//静态变量和公共抽象方法的集合,形式上类似于一个类
//接口中定义的变量、方法都隐含默认的修饰符
interface Parent{
    String name;    //等价于 public static final String name;
    void say();     //等价于 public abstract void say();
}
//其功能与抽象类类似,都是用于为对象定义共同的行为,概述一个类的外围能力

怎么来实现接口中的抽象方法呢?

我们需要用类来实现接口,用到关键字(implements

//代码接上
interface Person{
    void work();
}
//一个类可以用于实现多个接口
class Child implements Person,Parent{
    //ps:在实现时一定要加public ,因为原方法的权限是public ,不能降低方法的可视性
    public void say(){
        System.out.println("实现say()函数");
    }
    public void work(){
        System.out.println("实现work()方法");
    }
}

接口之间也是可以继承的,我认为没有很大意义,不过是先提前把接口都装到一个子接口中,然后实现时只用写一个罢了

interface All extends Person,Parent{
    void all();
}
GradedaoImplement gd=new GradedaoImplement();
		SqlSession session=GetSqlSession.createSqlSession();
		String courseName=req.getParameter("courseName");
		List<Grade> gradeList=gd.getGrade(courseName,session);
		req.setAttribute("gl", gradeList);
		req.getRequestDispatcher("showGrade.jsp");
//实现接口时,必须实现该接口继承的所有接口。
class Child implements All{
    public void all(){
        System.out.println("实现all()函数");
    }
    public void say(){
        System.out.println("实现say()函数");
    }
    public void work(){
        System.out.println("实现work()方法");
    }
}

sum:由此我们看出,interface相比抽象类更加强大,因为其不论是 接口之间的继承、还是 类来实现接口 都可以有多个。

而抽象类/类之间的继承都只能是单继承。

6.多态
package pers.hxy.begin;
class A{
	public String say() {
		return "I'm your grandpa : A";
	}
}
class B extends A{
	public String say() {
		return "I'm your mother : B";
	}
}
class C extends B{
	public String say() {
		return "I'm your sonC";
	}
}
class D extends B{
	public String say() {
		return "I'm your sonD";
	}
}

public class Test2 {
	public static void main(String[] args) {
	A person1=null;
	person1=new B(); //使用A类型变量引用B类型 A->B向下指,可以直接指
	System.out.println(person1.say());
	person1=new C();//使用A类型变量引用C类型
	System.out.println(person1.say());
	person1=new D();//使用A类型变量引用D类型
	System.out.println(person1.say());
	System.out.println("--------------------------------");
	B person2=(B)person1;//向下转型,可以看作将person2指向person1,即向上指的时候,因为是向上指,所以要将被指对象降级再转型
	System.out.println(person2.say());//调用方法还是由实际类型决定
	C person3=(C)person2;  
	System.out.println(person3.say());
	}
}
image-20211002220803446

错误原因:编译时,检测的是变量的声明类型,即B类型向下转化为C类型,但再运行时,转换的是变量的实际类型,即D类型到C类型的转换,而C&D类型之间并没有关联,故不能通过强转实现转换。

包(package)
1.关于包
  • 包的定义:形式上:是一组相关类和接口的集合 功能上:是区别类的名字空间的机制(不同包中类的名字可以相同,提高了复用性)

  • 包的规范:(三个一)

    般都小写;必须是程序代码中的第行可执行代码;package语句最多只能句;

    命名规则:公司域名反转作为包名(略)

2.带包编译命令
//引言:之前手动编译时,我们先将包对应的目录文件夹一个个手动创建好,在再其中写一个java源文件,然后编译运行
//实际上这一切都可以用命令提示符完成,只需提前将package写入java文件
package pers.hxy.helloworld
public class Person{
    public void say(){
        System.out.println("hahaha");
    }
}
//1.使用 javac -d.Person.java 编译源文件
//-d表示生成包对应的目录,.表示编译好的字节码文件放入当前文件夹中
//使用java pers.hxy.helloworld.Person运行命令(采用包名.类名的方法:可以理解为先切换到源文件所在的目录)

//java应用程序打包  
//更方便的给别人使用
//在要打包的顶层目录的上一级目录打开命令行窗口
jar -cvf xxx.jar pers(顶层目录名)
//然后添加环境变量,就over了
set classpath=.;D:\新建文件夹\helloword\src\xxx.jar  相关路径
//补充:解压包命令(解压到当前目录)
jar -xvf xxx.jar
2.import语句

public所修饰的类允许跨包使用,但必须引入该类所在的包

//引入位置:package语句之下,类定义之上
//两种引入形式
//1.引入类: 1个或多个  不能只导入包名
import 包名.类名
import 包名.*
//2.加static引入某个类的静态成员/方法  一个/多个     不能只导入类名
import static 包名.类名.成员名
import static 包名.类名.*
    //注意:直接用import static引入静态变量之后,直接使用变量即可,无需加类名调用(你又没有引入该类:))
3.java常用包(内置的)

java.lang:核心包(如String,Math,System等),系统自动导入,无需手动

java.util:工具包

4.Lambda 表达式

1.关于Lambda 表达式

实际上就是js中的箭头函数,只是=> 变成了->

//关于箭头函数的讲解(我的理解:匿名函数的变形)
(a,b)->{a-b} //括号中是参数列表,参数类型可省略,若只有一个参数,则可以不加括号
   			 //{}中是函数体,若只有一条语句,{}、return 都可以省略
			 //其他省就省了,为啥return关键字也可以被省略呢?原因是,编译器会认为:既然只有一个语句,那么这个语句执行的结果就				应该是返回值,所以return也就不需要了。

2.Lambda 表达式的意义

简化某些接口的实现(函数式接口)实际上是简化某些接口中抽象函数的实现

在以前,我们实现一个接口的抽象方法,需要用一个类去实现,非常麻烦

而对于:函数式接口 :仅包含一个抽象方法(ps:但是可以包含多个非抽象方法:静态方法,默认方法),则可以直接用Lambda 表达式实现

public interface ServiceOne{
    //唯一一个抽象方法
    void printmessage(String message);
    //默认方法不是抽象方法
    default void pringMessage2(String message){
        //方法体
    }
}
public class Testlam{
    public static void main(String[] args){
        //实现ServiceOne接口
		ServiceOne service1=s->System.out.println(s); //实现直接打印功能
        ServiceOne service2=s->System.out.println(s+"!");//实现打印且加感叹号功能
        ServiceOne service3=s->System.out.println(s+"haha");//实现打印且加haha功能
        service1.printmessage("I'm your father ");
        service2.printmessage("I'm your father ");
        service3.printmessage("I'm your father ");
    }
}
//输出:
//I'm your father 
//I'm your father !
//I'm your father haha

我们发现通过lambda表达式,可以直接实例化一个ServiceOne接口对象,且该接口中的抽象方法已经被填充!!!

通过Lambda表达式,可以实例化一个接口对象,且为其实现抽象方法,不同接口对象,可以实现不同方法。

不同对象调用同一方法名,实现不同功能(怎么有股多态那味儿)

异常
1.基础概念
  • 异常是一个在程序执行期间发生的事件,它中断了正在执行程序的正常指令流。
2.异常类别

java将异常封装到一个类中,出现错误时,会抛出异常。

Java类库中定义了异常类,他们都是Throwable的子类。即:Exception(异常)&Error(错误) 各自都包含大量子类

  • Error:程序无法处理的错误。描述了运行系统的内部错误,以及资源耗尽的问题。由JVM抛出。大多与代码编者本身无关。

  • Exception:程序本身可以处理的异常。

    • RuntimeException(运行时异常):运行期间,JVM抛出的异常,如那些:可以通过语法检测,但是最终在控制台报错。

      (此类错误常常能准确定位到发生错误的代码段,通过错误调试解决)

    • CheckedException(可检查异常):编译期间出现异常。必须进行处理。也就是写代码出现红线的错误

3.异常的处理!!!
img
  • try-catch处理异常
    public class TestThrow2 {
    
    	public static int div(int a,int b){
    		//if(b==0) {
    			//throw new ArithmeticException("不能输入零!!!");
    		//}
    		return a/b;
    	}
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		try {
                //若发现异常,则将产生的异常对象抛出
    			int val=div(10, 0);    //若该步发生了异常,则将跳过后续代码,直接进入catch,
    			System.out.println(val);
                //若try中抛出的异常对象类型符合,catch中定义的,则传入相应的catch中
    		}catch(ArithmeticException e){
    			System.out.println(e);
                System.out.println(e.getMessage());//getMessage():Throwable常用方法:异常对象信息
    			System.out.println(e.toString());//toString() :Throwable常用方法:返回异常类全名及异常对象信息
    		}finally{
                /*xxx代码*/
            }
    //		int val=div2(10, 0);
    //		System.out.println(val);
    		System.out.println("hah");
    	}
    }
    //输出结果:
        //java.lang.ArithmeticException: 不能输入零!!!
    	//不能输入零!!!
        //java.lang.ArithmeticException: 不能输入零!!!
    	//hah        -->接使用异常处理的意义
    //讲解:
    try{
        可能会发生的异常的程序代码
    } catch(异常类型1 e1 ){
        针对异常进行处理的代码
    }catch(异常类型2 e2){
        针对异常进行处理的代码
    }...
    finally{
       释放资源代码;
    }
    

    关于finally

    //取部分代码:
    int a=1;
    try {
    			int val=div(10, 0);   
    			System.out.println(val);
    		}catch(ArithmeticException e){
    			System.out.println(e);
    			System.out.println(e.toString());
        		//System.exit(0);  jvm退出指令
        		return a  //只是为了测试,随便乱返回一个
    		}finally{
        		a++;
                system.out.println("ha");  
        //此时finally代码仍会执行,就算不发生异常,finally也会执行,所以:finally里面的代码最终一定会执行(除了JVM退出)
            }
    //try中处理return的机制:先保存return值,在执行finally,再取出保存值(也就是说:a会变,但原来的值已经被保存了)
    //最终返回的return值仍为1
    
  • 关于异常的嵌套
//由上面代码可知:只要try中发现异常对象,则立刻跳过try中后续代码,进入到相应的catch中,
//故若一个try中包含多个异常,则只能捕获出一种(其他可能出错的程序,都被跳过了),想要捕获到几种,则要采用嵌套
public class work1 {
	public static int chu(int a,int b){
		return a/b;
	}
	public static char say(char[] s) {
		return s[5];
	}
	public static void main(String[] args) {
        //异常嵌套:使可捕获到多种错误
		try{
			try {
				try {
                    //先测试下标越界
					char[] strs= {'c','h','a'};
					System.out.println(say(strs));
					}catch(IndexOutOfBoundsException e2) {
						System.out.println(e2);
					}
                //再测试算数异常
				int c=chu(10, 0);  //上层错误代码一定要放到下层try的下面,不然,下层try的代码将直接被跳过
				System.out.println(c);
				}catch (ArithmeticException e1){
					System.out.println(e1);
				}
                //测试空指针异常
				//字符串未初始化时会抛出空指针异常
				String work=null;
				System.out.println(work.length());
			}catch(NullPointerException e3) {
				System.out.println(e3);
			}finally {
			System.out.println("异常处理完毕,程序结束");
		}
	}
}
4.Throws与Throw

所有系统定义的编译和运行异常(即非自定义的)都可以由系统自动抛出,如上例:main调用div方法,div方法产生异常,但方法内部并没有处理异常的代码,故自动将异常对象抛出调用者——>main,main中有处理异常的方法,故程序正常运行。

如果是多级调用,则将从异常产生处一层层抛出,直到可处理异常的方法中,若到了主函数还没有,则由虚拟机进行处理,程序中断。

  • Throws关键字用于抛出异常对象

    Throws的意义就是向我们声明:如果该方法产生异常,该方法不处理异常,由他的调用者帮忙处理

  • Throw关键字用于抛出异常的实例对象

    //语法格式:
    throw new 异常对象();
    throw new 异常对象("xxx";  通过throw方式还可以自定义异常对象信息
    

    作用:1.指明此处一定有异常对象(这点实际上没多大用,因为系统定义的异常都会被自动抛出)

    2.有些错误jvm看来不是错误,我们可以自己手动引发错误!!来提醒其他开发者

5.自定义异常
package pers.hxy.begin;
class DivException extends Exception{
	public DivException() {
		super();  //可以不用写,默认会调用父类的无参构造
	}
	public DivException(String message) {
		super(message);  //实例化有参子类时,调用父类的有参构造
	}
}
public class TestThrow {
	public static int div(int a,int b) throws DivException{//手动抛出该实例(自定义异常对象不能被自动抛出)
		if(b==0) {
			throw new DivException("错误,除数不能为0");  //产生异常对象实例,并定义了异常对象信息
		}
		return a/b;
	}
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		try {
			int val=div(10, 0);
			System.out.println(val);
		}catch(Exception e){    //因为Exception是所有异常类的父类,所以用其捕获该异常对象
			System.out.println(e);
			System.out.println(e.toString());
		}
	}
}
//输出:
pers.hxy.begin.DivException: 错误,除数不能为0
pers.hxy.begin.DivException: 错误,除数不能为0

对于自定义的异常对象,需要手动产生,手动抛(当然不想抛,就在产生实例的那个方法中处理异常呗)

6.总结:使用异常处理的意义

由第一个代码例中我们发现,尽管产生了异常,但由于我们使用try-catch进行了捕获操作,程序仍然完整执行了(hah被输出,如果没有异常处理,则程序在异常的那一步则直接终止)。

异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。

基础类库(java自带的类)
Scanner类

基于正则表达式的文本扫描器,功能:获取动态传入的参数值

有多个构造方法,用于接收不同的数据来源

import java.util.Scanner;//Scanner类位于java.util包

public static void main(String[] args){
    //System.in代表标准输入,即键盘输入
	Scanner sc=new Scanner(System.in);
    //hasNext() 如果当前输入流还有值,则返回true,没有则暂停,等待键入
    //用hasNext()作判段条件,输入流有值则执行,无值将等待输入,有了又执行,然后相当于程序永远不会终止,直到输入exit
    while(sc.hasNext()){
        //next()如果当前输入流有值,则直接取走一个,没有则程序暂停等待键入
        String s=sc.next();
        if(s.equals("exit")){
            break;
        }
        System.out.println("输入的内容为:"+s);
    }
    sc.close();  //释放资源
}
//ps:hasNextxxx() xxx可以为Int Long 等代表基本类型的字符串,如果值判断是否包含下一个字符串,则用hasNext()

因为system.in属于IO流,一旦打开,它一直在占用资源,因此使用完毕后切记要关闭。

System类与Runtime类

java可以通过 **System类与Runtime类中的属性方法 **与程序的系统平台进行信息的交互

程序不能创建System类与Runtime类的对象

  • System类

    它的属性和方法都是静态的,所以就算不能实例化System对象也不影响调用

    //常用方法
    long start=System.currentTimeMillis() 
         //返回当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
        //返回值为long类型
    String name=System.getProperty(String key)//注意传入的是字符串
        //通过键获取当前系统属性中键KEY对应的值
        //如:
        System.getProperty("user.name"); //当前系统用户名为           Lenovo
        System.getProperty("user.dir");   //当前用户工作目录
        System.getProperty("os.name");    //当前系统名称
    
    System.exit()//终止当前正在运行的java虚拟机  无返回值 void
    
  • Runtime类

    Runtime类代表Java程序的运行时环境 ( JRE=JVM+Api ),每个java程序都有一个与之对应的Runtime实例

    Runtime类的属性和方法不都是静态的,所以需要通过静态函数getRuntime()方法创建对象

    //通过静态函数getRuntime()方法获取当前java程序的Runtime对象
    Runtime r=Runtime.getRuntime();
    long start=r.freeMemory();//返回Java虚拟机中的空闲内存量
    		  =r.totalMemory();//返回Java虚拟机中的总内存量
    		  =r.maxMemory();//返回Java虚拟机中的可用最大内存量
    
    r.exec("xxx") //单独的进程中执行指定的字符串命令
    
Math类

Math类包含了许多数学运算的方法。且基本都是静态的。

Math类的构造方法是私有的,所以不能被实例化;

Math类被final修饰,因此不能有子类。

import java.lang.Math;  //Math位于lang包中
//列几个常见的
//Math类提供了两个静态常量E(自然对数)、 PI(圆周率)
Math.E //2.718281828459045
Math.PI//3.141592653589793
//以下三个方法只能用于Int型
Math.abs(-10)  //10绝对值函数
Math.max(10,6)  //10  最大值函数
Math.min(10,6)  //6   最小值函数

Math.random(); //产生[0,1)的double型随机数
Random类

用于生成一个伪随机数,范围更加广

//有两个构造函数
Random r=new Random();  //无参构造,以当前时间作为种子,相当于每次的种子都不一样,故每次生成随机数不一样
Random r=new Random(10);  //传一个指定参数作为种子,每次生成随机数一样

r.nextDouble() //返回一个0.0~1.0之间的double型随机数,
r.nextDouble()*100//返回一个0~100之间的double型随机数,
r.nextFloat() //返回一个0.0~1.0之间的Float型随机数,
r.nextInt()   //返回一个int
r.nextInt(n)   //返回一个[0,n)之间的Int
Date类
//创建日期的方式
import java.util.Date
Date date1=new Date();  //调用空构造方法,创建当前日期
Date date2=new Date(xxxxxxxxxx);  //返回距离1970 1/1 00:00 xxxxxxxxxx毫秒的日期
Calendar类

Calendar类是抽象类不能被实例化可以通过静态方法getInstance()获取实例

//Calendar类提供了关于当前日期的静态常量!!
//YEAR   MONTH   DAY_OF_MONTH   HOUR_OF_DAY   MINUTE   SECOND   MILLISEECOND
// 年      月         日              时          分       秒          毫秒

上述常量使用时不能直接使用,必须通过get()方法获取!但get()方法需要实例对象调用

import java.util.Calendar;
Calendar calendar=Calendar.getInstance();  //通过getInstance()静态方法获取Calendar实例
System.out.println(calendar.get(Calendar.YEAR)); //通过get()方法得到常量值
System.out.println(calendar.get(Calendar.MONTH));		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));		System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
DateFormat类

DateFormat类是抽象类,不能被实例化,可以4种通过静态方法获取,不同风格的日期/时间格式器

//获取日期格式器
DateFormat dateFormat=DateFormat.getDateInstance();
//利用格式器将时间日期格式化
dateFormat.format(new Date())//2021年10月15日
//获取时间格式器
DateFormat dateFormat2=DateFormat.getTimeInstance();
dateFormat2.format(new Date())   //下午4:45:39
SimpleDateFormat类

DateFormat类的子类,可以直接使用父类格式方法 format()

作用:创建实例时,指定格式器的格式

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");//创建年月日格式为 xxxx-xx-xx 的格式器 如:2021-10-05
SimpleDateFormat sdf2=new SimpleDateFormat("Gyyyy-MM-dd hh:mm:ss:SSS");//G表示公元  公元2021-10-05 05:44:18:538  SSS表毫秒
System.out.println(sdf.format(new Date()); //2021-10-15
String类

关于拼接问题:

字符是char 类型,字符串是String 类型
1、数字拼接char,得到的还是数字,相当于和它的ASCII编码相加(如果定义成String 会编译错误)
2、数字拼接String,得到的是String
3、数字同时拼接char 和 String,就看和谁先拼接,和谁后拼接
4、String 拼接任何类型,得到的都是String

1.String类的初始化

关于String类:String类表示不可变的字符串,一旦其被创建,对象中的字符序列就不能再被改变。

//1.直接赋值初始化
String s1="abc";
//JVM首先会去常量池中查找是否存在"abc"这个对象,如果不存在,则在常量池中创建"abc"这个对象,然后将池中"abc"这个对象的引用地址返回给"abc"对象的引用s1,这样s1会指向字符串常量池中"abc"这个字符串对象;如果存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给引用s1

//2.构造方法初始化
String s2=new String();  //初始化一个空字符对象
String s3=new String(['x','y','z']);  //新建一个String对象,字符序列为字符数组当前包含的字符
String s4=new String("xyz")           //新建一个String对象
//采用new关键字新建一个字符串对象时,JVM首先在常量池中查找有没有"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,故s3!=s4。
2.String类常用方法

由于String类表示不可变的字符串,故大多都是 用于判段、获取信息、得到一个新的对象

String str="hello.com";
//利用索引获取该位置的值
System.out.println(str.charAt(1));//e  
 //将字符串转化为一个字符数组
char[] c=str.toCharArray(); 
//按指定符号分隔,拆成字符串数组
String[] sp=str.split("\\.") //先将.转义为 \. 再将\转义\\  注意:split中的参数一定是string型 
System.out.println(sp[0]); //hello
System.out.println(sp[1]); //com
//字符串截取
System.out.println(str.substring(2));//llo  从索引2截取到末尾
System.out.println(str.substring(2,4)); //ll  截取2,3号位
//大小写转换
String str1=str.toUpperCase(); 
System.out.println(str1);//HELLO.COM
String str2=str.toLowerCase();
System.out.println(str2);//hello.com
//完成字符串中的字符替换,替换全部的
String newstr=str.replace('.', '#');  //hello#com  注意replace是用于字符替换,而不是字符串替换
System.out.println(newstr);
//字符数组转换为字符串
String.valueOf(c);  //char[] c;
//关于字符串的比较问题:equals(xxx)   VS    ==
//equals() 比较的是字符串的内容是否相同,这正是我们需要的
//==  比较的是字符串的地址是否相同
public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);   		//true
        System.out.println(s1.equals(s2));      //true   
}
因为他们的地址都是常量池中"hello"对象的引用地址,所以s1==s2

 public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "HELLO".toLowerCase();
        System.out.println(s1 == s2);               //false
        System.out.println(s1.equals(s2));          //true
}
StringBuffer类

StringBuffer用于描述可变序列。不用生成新的对象,可在原来序列上修改

StringBuffer类常用方法(包含String类,这里不重复写)
StringBuffer sb=new StringBuffer("hh");
//1.末尾追加内容
sb.append('a');
sb.append("\t");
sb.append("just");
System.out.println(sb); //hha  just
//2.指定位置加入内容
sb.insert(1,"a");
System.out.println(sb);  //hhaa  just
//3.字符串反转
sb.reverse();  //tsuj  aahh
//4.删除指定范围字符串
sb.delete(4,5);  //tsujaahh
StringBuilder类

StringBuffer是线程安全的,而StringBuilder是线程不安全的,故其效率更高

多线程

基本概念

多线程:一个进程在执行过程中产生多个更小的程序单元,称为线程

每个运行的程序就是进程,进程可以同时执行多个任务,每个任务就是线程。

进程在系统中独立存在,多个进程可以在单个处理器上并发执行且互不影响。

IO流

输入:从外部存储–>程序 输出:程序–>外部存储

抽象类OutputStream 是一切字节输出流的基类,InputStream是一切字节输入流的基类

字节输出流

package pers.hxy.begin;

import java.io.*;

public class Testio {
	public static void main(String[] args) throws IOException {
		// TODO 自动生成的方法存根
		//创建字节输出流对象(使用outputStream的子类)
		FileOutputStream io1=new FileOutputStream("hello.txt");
		
		//若想实现追加写入,即每一次运行都会接着上面的写,而不是从头开始重新写,
//		FileOutputStream io1=new FileOutputStream("hello.txt",true); //将从末尾开始追加
		
		//三种写出方式
		//1.一次性只写一个int 自动根据ascII码转化为字符
		io1.write(97);  //a    
		byte[] by= {97,98,99,100};  
        
		//2.一次性写入一个字节数组
		io1.write(by);   //abcd   
		//小tips可以自动将想输入内容转换成字节数组,再传入
		byte[] by2="whoYouWANT".getBytes();
		io1.write(by2);
        
		//2.1 写入一部分数据
		io1.write(by2,0,2); //wh 从0开始写2个
		
		//写数据的时候想换行怎么办?
		io1.write("\r\n".getBytes());   //想在windows下识别换行:\r\n 
		
		//释放资源,关闭输出流
		io1.close();
	}
}   
字节输入流
//字节输入流
package pers.hxy.begin;
import java.io.*;
public class Testio {
	public static void main(String[] args) throws IOException {
		// TODO 自动生成的方法存根
		//创建字节输入流对象(使用InputStream的子类)
		FileInputStream fis=new FileInputStream("hello.txt");
		
		//读取数据
		//1.读取一个数据  注意:不管什么流,用.read()返回的都是int类类型
		int b=fis.read(); 
		System.out.println((char)b); //a
		System.out.println(b);     //97
		
		//1.1.常用:读取全部数据
		int by;
		while((by=fis.read())!=-1) {
			System.out.print((char)by);
		}
		
		//2.一次性读取定长的数据(用指定长度的字节数组去装读取的数据,只能读取这么多)
        byte[] bys=new byte[5];
		int len;
		len=fis.read(bys); //len:此时read()返回实际读取的字节数,读取到的数据存在了bys中
		System.out.println(new String(bys,0,len)); //将字节数组转换为对应的字符串
		System.out.print(bys);
        
        fis.close();
	}
}
  • 实例:复制图片

数据源---->----读----->-----程序------>-------写-------->-------目的地

public static void main(String[] args) throws IOException {
		FileInputStream fis=new FileInputStream("D:\\2021前端---jQuery\\image\\monster4.png");
		//将文件内容复制到D盘下的end文件中
		FileOutputStream fos=new FileOutputStream("mn.png");
    
    //方1:基本字节流一次性读写一个字节
//		int by;
//		while((by=fis.read())!=-1) {        //这种方法最慢!效率最低
//			fos.write(by);
//		}
    
    //方2:基本字节流一次性读写一个字节数组(1024个字节)
		byte[] by=new byte[1024];          
		int len;             
		while((len=fis.read(by))!=-1) { 
			fos.write(by,0,len);
		}
    
		fis.close();
		fos.close();
		}
	
 //方3:字节缓冲流一次性读写一个字节数组(这种方法最快)
    略,就是对输入流和输出流做一个封装,改一下最上面两行代码即可
字节缓冲流

实际上就是对输出流 和 输入流的一个 封装

public class Testio2 {

	public static void main(String[] args) throws IOException {
		BufferedInputStream bin=new BufferedInputStream(new FileInputStream("hello.txt"));
		int len;
		byte[] bys=new byte[1024];
		while((len=bin.read(bys))!=-1) {
			System.out.println(new String(bys,0,len));
		}
		BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("hello.txt"));
		bos.write("I LOVE YOU!".getBytes());
		
		bin.close();
		bos.close();
	}
}
字符流

字符流=字节流+编码方式

字符流有两个抽象基类:Writer Reader

OutputStreamWriter:字符输出流 读取字符,采用指定字符集将其编码为字节

InutputStreamReader: 字符输入流 读取字节,采用指定字符集将其解码为字符(若未指定,则都采用默认字符集UTF-8)

用字节流操作汉字不是很方便,所以Java提供字符流

一个汉字: 3个字节(UTF-8编码) 2个字节(BGK编码)

无论采用哪种存储方式,第一个字节都是负数

常见编码表:ASCii字符集 GBK字符集(简体中文码表) Unicode(标准万国码)(其中UTF-8是最常用的编码方案)

  • 字符输出流
public class Testio2 {
	public static void main(String[] args) throws IOException {
		//创建一个使用默认字符编码的字符输出流对象
         //构造函数参数必须是OuputStream类
		OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("hello.txt"));
		//直接写一个字符(可以写对应的int)
		osw.write(97);
		//直接传入一个字符串
		osw.write("hahas\n");
		//传入字符串的一部分
		osw.write("我爱你",0,2);
		osw.flush();//字符流写数据的时候会先累积在缓冲区里面,若想立即写入,则需要手动刷新
       
		osw.close();  //关闭Io流前,会自动进行刷新
	}
}
  • 字符输入流

    public class Testio2 {
    
    	public static void main(String[] args) throws IOException {
            //构造函数参数必须是InputStream类
    		InputStreamReader isr=new InputStreamReader(new FileInputStream("hello.txt"));
            //一次读取一个字符
    //		int ch;
    //		while((ch=isr.read())!=-1) {
    //			System.out.print((char)ch);
    //		}
            //一次读取一个字符数组
    		int len;
    		char[] c=new char[1024];
    		while((len=isr.read(c))!=-1) {
    			System.out.print(String.valueOf(c));
    		}
    		isr.close();
    	}
    }
    
  • 字符缓冲流

//字符缓冲输入流 
BufferedReader br=new BufferedReader(new FileReader("hello.txt"));
//也可以这样:PS:FileReader内置一构造函数生成FileInputStream对象,然后调用父类构造生成Reader类
//BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("hello.txt")));
//字符缓冲输出流
BufferedWriter bw=new BufferedWriter(new FileWriter("hello.txt"));


//缓冲流的特有功能
bw.newLine();  //换行
br.readLine();//一次读一行字符

String line;
while((line=br.readLine())!=null) {
	System.out.println(line);
}

关于:JAVA GUI

Graphical User Interface (GUI)图形化的用户界面

1.2Java提供了三个主要包做GUI开发:

java.awt 包 – 主要提供字体/布局管理器

javax.swing 包[商业开发常用] – 主要提供各种组件(窗口/按钮/文本框)

java.awt.event 包 – 事件处理,后台功能的实现。

Swing组件

(1)顶层容器::常用有JFrame,JDialog 绝大多数Swing图形界面程序使用JFrame作为顶层容器

(2)中间容器:JPanel相当于div,JOptionPane,JScrollPane,JLayeredPane 等,主要以panel结尾。

(3)基本组件:JLabel,JButton,JTextField,JPasswordField,JRadioButton 等。 标签、按钮、文本框、密码框、单选按钮

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值