• Java基础总结—基础篇


    JavaSE 笔记

    一、Java开发环境搭建

    、

    1、Java语言的特性

    • 简单性 : 相比C 和 C++来说,是简单的!
    • 健壮性 : 存在垃圾回收(GC)机制 供JVM调用,自动释放不用的内存
    • 可移植性、跨平台 :

    优点:一次编写到处运行 缺点:麻烦,运行Java程序必须现有一个JVM

    2、JDK、JRE、JVM

    • JDK(Java Developer’s Kit): Java开发工具箱

    • JRE(Java Runtime Environment): Java运行时环境

    • JVM(Java Virtual Machine): Java虚拟机 (注意:JDK 包括 JRE 包括 JVM)

    3、Java的加载与执行

    、

    注意:源代码(xxx.java文件)不参与执行,参与执行的是编译执行后生成的字节码文件(xxx.class文件)!

    两个阶段,可以在不同的操作系统上执行

    JVM会把字节码文件解释为相应的二进制文件供操作系统识别

    4、JDK的下载

    官网:https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html

    下载完成后,双击执行.exe文件下一步即可

    注意:如果是JDK13,仅仅是内置一个JRE,如果是JDK8会再生成一个JRE!

    、

    5、环境变量 path

    path 环境变量就是给 windows操作系统指路的

    默认情况下,在Windows操作系统的Dos窗口下,windows只会在当前Dos打开的目录,和path指定的路径下去找命令!

    其他环境配置 :

    • JAVA_HOME 环境变量 :设置jdk的安装路径、抽取目录,相当于为一串路径起个别名!
    • classpath 环境变量 :让为我们的ClassLoader(类加载器)指明方向,让我们 java + 类名运行字节码文件时,类加载器不仅仅只在当硬盘中的当前目录下加载字节码文件,可以自定义类加载器的寻找路径!
    • Java程序在运行时,首先会启动JVM(Java虚拟机),然后JVM会去启动“类加载器classloader”负责去硬盘上找“类”对应的“字节码”文件。默认情况下类加载器(classloader)会从当前路径下找。
    • 2.classpath环境变量的作用是给类加载器指路的。
      在没有配置环境变量classpath的时候,默认从当前路径下加载
      如果配置了环境变量classpath的话,就只能从指定的路径下加载类。
    • 3.classpath环境变量不属于windows操作系统,classpath环境变量隶属于java。
      classpath环境变量是java特有的。
    • 使用Idea运行字节码文件的时候默认是在字节码同一目录,所以能找到!

    JDK中rt.jar、tools.jar和dt.jar作用

    • rt.jar :

      这个文件是极为重要的一个文件,rt是runtime的缩写,即运行时的意思。是java程序在运行时必不可少的文件。
      里面包含了java程序员常用的包,如java.lang,java.util,java.io,java.net,java.applet等,默认就在Root ClassLoader的加载路径里面

    • tools.jar

      系统用来编译一个类的时候用到的 也就是javac的时候用到

    • dt.jar

      dt.jar是关于运行环境的类库,主要是swing的包 你要用到swing时最好加上

    JDK13新特性:直接java + Hello.java就可以运行,也不会生成Class字节码文件【了解即可!】

    6、Java中的注释

    • 方式一:// 注释内容 ,单行注释
    • 方式二:/* 注释内容 */ ,多行注释
    • 方式三:/** 注释内容 */ ,Javadoc注释,这里的注释会被javadoc.exe命令解析提取出来,并生成到帮助文档当中!

    命令:Javadoc -d 指定生成目录 xxx.java 【了解即可】

    7、Public Class 和 Class

    一个XXX.java文件能有多个Class,可以没有Public Class,【得出一个类就是一个字节码文件、体现出一个java文件可以生成多个字节码文件!】

    一个xxx.java文件如果有且只能有一个被public修饰的类,并且与文件同名!

    一个Class只能有一个入口函数 public static void main(string[] args){ }

    二、标识符与关键字

    标识符可以标识:类名、方法名、接口名、常量名、变量名 …

    1.标识符命名规则

    1. 只能由 数字、字母、下划线_ 、美元符号$ 、构成
    2. 不能数字开头,严格区分大小写、不能含有空格、关键字不可作为标识符
    3. 理论上无长度限制

    2.标识符命名规范

    规则与规范的区别:规则相当于法律,规范相当于道德! 不可违背法律,但是最好遵守道德!

    • 最好见名知意
    • 遵守驼峰命名方式
    • 类名、接口名首字母大写,后面每个单词首字母大写 例: BlogInputController{ }
    • 变量名、方法名 首字母小写,后面每个单词的首字母大写 例 : addBlog( )
    • 常量名 全部大写,单词间用下划线_隔开 例 : MATH_PATH = 3.1415926

    3.关键字

    SUN公司开发Java语言的时候,提前定义好的一些具有特殊含义的单词!例如:public、class 、static 、void 等

    、

    3.1、static关键字

    static可以修饰方法、变量【static所修饰的即为类级别的!】

    //举例:
    class  StaticTest{
        //以下变量和方法都属于实例变量/方法,访问需要"引用."的方式,需要new对象访问!
        int age ;  
        
        public void setAge(){  };
        
        //以下变量和方法都属于静态变量/方法,访问直接"类名."的方式即可!
        static int name ;
        
        public static void setName(){  };
    }
    

    静态变量的用途:一般用于对象的某个属性不会改变,例如static string country = “中国” ;会直接在类加载的时候在方法区中初始化,且只保留一份,不会浪费堆内存,不需要new对象就有值,因此构造方法,也不用添加该属性,类似默认值!

    静态代码块

    静态代码块,在类加载时执行,且只执行一次,并且在main方法之前执行,【一般在静态代码块中记录一下日志,了解即可】

    //如果有多个静态代码块,自上而下顺序执行!
    static {
        System.out.println("静态代码块 01!")
    }
    static {
        System.out.println("静态代码块 02!")
    }
    
    //测试:静态代码块和静态变量的执行顺序!
    
    class StaticTest{
        //静态变量,类记载时被初始化!
        static int age = 20 ;
        
        //静态代码块,类加载时执行!
        static {
            Syste.out,println(""age = "+ age); //因为都是类加载时执行,所以可以访问到,前提:还得是静态变量定义在代码块之前!
        }
        //入口函数                  
       public static void main(){
       	
       }
    }
    

    3.2、this关键字

    this是一个变量、是一个引用,this保存当前对象的内存地址,指向自身,且this存储在堆内存中,对象的内部

    **this使用在实例方法中,代表当前对象!**常用于set、get方法当中,也因此set,get方法为实例方法,!

    如果方法中可以直接访问实例变量,那么该方法一定是实例方法!

    注意:常常可以省略,但是在set方法中一般不省略!为的是避免参数和属性重复,导致set失败!

    this() 使用在构造方法中

    语法:this(实际参数列表) ,构造方法调用构造方法

    class Data{
        int year ;
        int month ;
        int day;
        public Data(){
            this(year,month,day); //一般用于无参构造赋初值,且只能出现在构造方法的第一行,必须是第一个语句!
        }
        public Data(int year,int month,int day){
            this.year = year ;
            this.month = month ;
            this.day = day ;
        }
    }
    

    好处:代码复用,减少代码量!

    3.3、super关键字

    与this做对比学习!

    结论:当一个构造方法的第一行,既没有this也没有super,默认会有一个super( ),表示当前子类构造方法,调用父类的无参构造方法,所以,必须保证父类的无参构造方法是存在的!

    //super测试
    public class Test{
        public static void main(string[] args){
            new B();   //输出:构造A 构造B
        }
    }
    class A{
        public A(){System.out.println("构造A")}
    }
    class B exdents A {
        public B(){
            super();  //这个super一般省略,等价于new A ( ),先初始化父亲,才能new儿子!
            System.out.println("构造B")}
    }
    

    super的JVM内存图

    注意:虽说new一个对象一直在调用父类的构造方法!其本质还是new的一个对象,只是将父类的特征继承过来!super( )可以看作,初始化当前对象的夫类型特征;

    3.4、super与this的区别:

    this:

    1. this只能出现在实例方法中
    2. 两种语法:this. 和 this ( )
    3. this在大部分情况下可以省略,但是在区分局部变量和实例变量时,不能省略this
    4. this( )只能出现在构造方法第一行,表示调用别的构造方法!

    super:

    1. super能出现在实例和构造方法中
    2. 两种语法:super. 和 super()
    3. 不能使用在静态方法中
    4. super在大部分情况可以省略,但是
    5. super ( ) 同样只能出现在构造方法第一行,表示通过当前子类构造方法去调用父类的构造方法!模拟的是,要想有儿子,就要先有父亲的原则、目的是:表示在初始化子类对象的时候,先初始化父类对象特征!

    结论:

    • this()和 super( )不能共存!
    • this()调用同类其他构造
    • super()调用父类构造方法
    • super . 表示当前对象的父类型特征的 后可以加属性或方法 表示访问父类的属性或方法、 this. 表示当前对象的
    • 默认是无参,()中通过参数列表判断执行那个构造方法!
    • 在子类无法访问父类的私有的方法,没有权限!

    3.5、final关键字

    final + 类 :final修饰的类无法被继承 ;

    final + 方法 : final修饰的方法无法被覆盖(无法重写);

    final + 局部变量 : final修饰局部变量一旦赋值,不可修改 【只能赋一次值】 ;

    final + 引用 :引用指向的堆内存不可修改,队形不可改,但是对象的属性可改 ;

    final + 实例变量 :new对象的时候,系统不会赋默认值null,必须手动赋值,一旦赋值,不可修改【实际开发中还需添加static修饰】!

    static final String COUNTRY : 就是定义常量 COUNTRY,在方法区被加载,而且只有一个 !

    总结:final 修饰的变量只能赋值一次!

    三、变量、数据类型、运算符

    前提知道:字面值(字面量):就是数据、是Java源程序的组成部分

    变量 : 内存当中存储数据的最基本的单元

    变量三要素 : 数据类型 + 变量名 + 字面值 【类型决定空间大小】【通过名字访问数据】【字面值就是保存的数据】

    1.变量的分类

    局部变量 : 方法体中声明的变量

    成员变量 : 类体内声明的变量

    注意:成员变量 = 实例变量(类体中定义的int age) + 静态变量(类体中定义的static int age);

    注意:局部变量只在方法体中有效,方法体执行结束,该内存就释放!

    2.变量的作用域

    作用域:变量的有效作用范围,出了大括号就不认识了!

    并且与其他变成语言一样,Java在访问变量的时候存在一个就近原则!

    扩展 :int a = 100 ; int b = a ;的赋值原理:将a变量的值复制一份给b变量,所以a、b是两块不同的内存空间

    3.数据类型

    一、基本数据类型:四大类八小种

    • 整数型 : byte(字节型) 【占1Byte空间】、short(短整型)【占2Byte空间】、int(整型)【占4Byte空间】 、long(长整型)【占8Byte空间】
    • 浮点型 : float(单精度)【占4Byte空间】、double(双精度)【占8Byte空间】
    • 布尔型 : boolean【占1Byte空间】
    • 字符型 : char【占2Byte空间】

    扩展:

    1M = 1024KB 、1KB = 1024Byte 、1Byte = 8 bit 一个bit(比特)相当于一个0或1 ,

    一个汉字占用2个字节,可用char来存储 例如 : char c = ‘宋’ ;但不可存’ab’,因为char读取一个字符后会直接找分号、ab是属于字符串!

    、

    **二、引用数据类型:**除了基本数据类型外的数据类型

    String 和 Class XXX 类型【自定义类型】如Student类

    java.math.BigDecimal类型,财务数据类型

    4.转义字符

    改变原本字符的含义!

    / 正斜杠 \ 反斜杠

    \ 是转义字符,会将后面紧挨着的字符转义! 遇到t为 \t 制表符, 遇到n为\n换行符、遇到"则失去其含义成为普通字符(不会再与另一个"配对)!

    5.类型转换

    规则:等号右边先执行,然后赋值给等号左边的变量

    类型转换的话:大容量转小容量,损失精度,如int a = 100L ; 小容量转大容量:没问题,如 long b = 100 ;

    int类型的上限是214748647,一般长度最多为9位!

    注意 :long = 214748648 ,报错因为等号右边不加L默认是整数类型字面值,但是又超出整数范围,所以报错!

    强制类型转换:如int a = (int) 100L ; 直接大容量转小容量,损失精度,编译报错,但是进行强转后,虽然编译能过但是仍会损失精度!

    强制类型转换的原理:砍去前面的字节!

    6.运算符

    例如:三目运算符:char c = sex ? ‘男’ :‘女’

    当sex == true时, c= ‘男’,当 sex == false时,c=‘女’!;

    接收用户键盘输入

    为变量赋值!

    public class keyInput{
        public static void main(string[] args){
            java.util.Scanner s = new java.util.Scanner(System.in) ; 
            int i = s.nextInt() ;   //输入整数,此处相当于C++中的 scanf("%d",&i); 
            String str = s.next() ; //输入字符串 
        }
    }
    

    四、控制语句

    1.选择语句

    • if 语句
    • switch 语句

    2.循环语句

    • for 循环
    • while 循环
    • do … . while循环

    3.转向语句

    • return : 结束当前循环!

    • continue :结束当次循环,进入下次循环

    • break : 直接跳出循环,只跳出一层循环!

    五、方法

    先了解方法在JVM的内存结构图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3uMKMYtU-1633792195624)(JavaSE.assets/image-20210827223131170.png)]

    方法区:类加载器将字节码文件加载到JVM当中后,将字节码文件放入方法区,然后找到字节码文件的入口main,然后执行!

    注意:只要是方法,无论是构造方法,静态方法,实例方法,都会压(push)栈的!

    1.方法重载 Overload

    同一个类中,方法名字一致,参数列表(参数的个数、参数的类型、参数的顺序)不一致即为方法重载

    2.方法的递归

    就是套娃! 写个题测试:递归求n的阶乘、递归求前n个数的和、递归求斐波那契数列、、、

    3.方法的覆盖/重写 Override

    A.Class exdents B.Class 当子类不满足从父类中继承来的的方法时!A类中重新改写继承过来的方法的方法体内容!

    条件:1.同一个方法 方法名字一致,参数列表一致,改写方法体内容,

    ​ 2. 如果返回值是基本数据类型,重写时,返回值类型必须一致。如果是引用数据类型(Object),则重写可以变小(Cat)一些!,但是意义不大,实际开发并不会这么写!

    ​ 3.权限不能更低

    ​ 4.异常不能更多

    ​ 5.静态方法,不谈覆盖,因为方法覆盖通常跟多态有关,静态方法覆盖也没意义!

    ​ 6.私有方法不能覆盖

    注意:当父类中的方法是protect,我们子类重写方法可以把权限升高为protect、public,但是如果父类中的方法是public,我们重写的时候这个权限是不能降低的,只能是public,而且抛出的异常只能更少不能更多!

    4.方法分类

    • 实例方法:对象(实例)里的方法,不含static
    • 静态方法:类里的方法,含static的方法
    • 构造方法:不可被调用,应用于开辟空间

    5.方法调用 *

    静态方法的调用:通过 “类名 . 方法名 ”,去调用,如果在一个类中,类名可以省略不写(本质就是编译后的字节码文件需要在同一级目录,字节码文件. ) ,【也可以通过引用调静态方法,会JVM会自动把引用转化为Class类,但是不建议使用

    实例方法的调用:通过 ”引用 . 方法名“,去调用,


    注意:在除了Main()方法中调用其他实例方法需要new实例之外,其他方法中调用不需要new对象,可以直接方法名调用

    六、面向对象

    特点:高内聚,低耦合,易扩展

    默认情况下,类中的变量分为局部变量和成员变量,以及静态方法

    但是,一个类如果被new(实例),那么这个new出来的就是该对象的实例,对象中的变量称作:实例变量,对象中的方法称作:实例方法

    创建对象(实例)对应JVM内存图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHHX59Ot-1633792195626)(JavaSE.assets/image-20210828183353062.png)]

    1.OOA、OOD、OOP

    • OOA(Object Oriented Analysis):面向对象分析
    • OOD(Object Oriented Design):面向对象设计
    • OOP(Object Oriented Programming):面向对象编程

    一个软件的开发过程:A(分析) ---->D(设计)----->P(编程)

    2.封装、继承、多态

    封装、继承、多态 是面向对象的三大特征

    2.1、封装

    封装的目的:对外提供简单的入口,不再暴露复杂的数据,保证数据安全

    • 采用privite将属性私有化,使得外部不能直接访问!

    • 然后提供该属性的,set(),get()方法!,相当于对外提供一个简单的读入口、和写入口,并且可以在set,get方法中设置关卡!

    要求严格遵守 set 和 get方法的规范:

    //set方法规范
    public void setAge(int age){    	//方法名规范:get+属性名且首字母大写
        this.age = age
    }
    //get方法规范
    public int getAge(){
        return this.age;
    }
    

    2.2、继承

    基本作用:子类继承父类,代码才可以复用 (单继承,一个类只能有一个父类)

    主要(重要):因为有了继承关系,才有了后面的,重写和多态!

    继承(extends) 的特性:

    • 子类可以继承除父类除构造方法外,所有的属性和方法!
    • 父类中privite修饰的私有属性,子类继承过来不能直接访问,可以通过间接的访问
    • 所有类默认继承Object类(所有类的根!)
    • 子类继承父类,父类中的属性和方法归子类所有,所以子类可以直接调用父类的方法!

    2.3、多态 【重点】

    多态:就是多种形态,编译时一种形态(静态绑定),运行时一种形态(动态绑定)

    • 向上转型 :子 ------> 父 (自动类型转换)
    • 向下转型 :父 ------> 子 (强制类型转换,需要加强制类型转换符)

    无论是向下转型,还是向上转型,两者必须要满足 继承关系

    class cat extends Animal {	 cat独有方法:eat() 、重写animal中方法:move() }
    class Bird extends Animal {	bird独有方法:fly()、重写animal中方法 move()}
    
    Animal a = new Cat()   a.move()  //向上转型
    Animal a2 = new Cat()  (Cat)a2.eat()  //向下转型  
        
    Animal a3 = new Bird()   Cat c = (Cat)a3  c.eat()  //报运行时异常java.lang.ClassCastException!即使编译能过!但是运行时a3本质还是一只鸟,Bird与Cat无继承关系,所以运行失败!
        
    因此得出结论向下转型(强转):存在风险!
    避免方式: 采用 instance of
    
    instance of 运算符

    a3 instance of Cat 在运行时动态判断,引用a3堆内存中指向的是否为一只猫!如果是 return true 否则 return false ;

    Animal a3 = new Bird()  ;
        if(a3 instance of Cat)  Cat c = (Cat)a3 ;  
    	c.eat() ;  
    

    为什么使用instance of ?

    public void test(Animal a){
        if(a instance of Cat) Cat c = (Cat) cat
    	else if(a instance of Bird) Bird b = (Bird) cat
    }
    //使用instance of 的话,再调用上述方法,使得Cat和Bird都能接收!
    

    3.抽象类

    类与类之间的共同特征,这些共同特征抽取出来就是抽象类,但是注意:抽象类无法实例化、是用来继承的!

    基础语法:

    • 格式:[修饰符列表] abstract class XXX
    • 抽象类的子类可以是抽象类,也可以是非抽象类
    • final不可修饰抽象类
    • 抽象类无法实例化,但是抽象类有构造方法,供创建子类对象使用考虑super!
    • 抽象类中不一定含有抽象方法,但是抽象方法只能存在于抽象类中!
    • 非抽象类类继承抽象类,必须重写抽象类中的抽象方法 【重要】

    3.1、抽象方法

    特点:

    • 没有方法体,以分号结尾 ;
    • 前面修饰符列表存在abstract修饰

    4.接口

    完全抽象的,是特殊的抽象类!

    基础语法:

    • 格式:[修饰符列表] interface XXX
    • 编译后也是一个字节码文件
    • 一个接口,支持多继承,且其中的元素都是公开的public !
    • 接口中只能存在常量(static final)+ 抽象方法
    • 接口中抽象方法的前缀(public abstract)可以省略,接口中常量前缀(public static final)也可以省略
    • 非抽象类实现接口,必须将接口中的抽象方法全部重写!【重要】

    开发中的使用:

    一个类支持继承单个父类,实现多个接口!

    面向接口编程,解耦合!

    5.导包机制

    字节码文件不在同一个包下,如果需要调用,需要把需要调用字节码文件的包导入import

    package

    1. 出现在java源文件第一行
    2. 不在源文件目录编译需要 javac 包名.xxx.java;
    3. 不在字节码文件目录运行需要 java 包名.xxx

    import

    1. java.lang包下不需要导入,由编译器javac自动导入

    2. import 包名+类名

    6.访问控制权限

    1. private 私有的:private表示私有的修饰的元素,只能在本类中用
    2. protect 受保护的:protect只能在本类、同包、子类中访问!
    3. public 公开的:public表示公开的,在任何位置都可以访问!
    4. 默认的:默认只能在同类或同包下访问

    7.API 和 API 帮助文档

    API(application program interface ):应用程序编程接口

    整个JDK类库就是javaSE的API ,例如:

    一般每个API都会配备一个API帮助文档:

    8.内部类

    在类的内部又定义一个新的类,被称为内部类

    • 静态内部类
    • 实力内部类
    • 局部内部类:匿名内部类

    跟记忆变量的分类保持一致!静态内部类和实例内部类在Class内部,局部内部类在方法中,外部不得访问!

    8.1、匿名内部类 *

    interface compute{ 
        public abstract int sum (int x, int y );		//接口
    }
    
    class mymath{
        public void mysum(compute c, int x, int y){
          int value = c.sum(x,y) ;
        }
    }
    
    public class Test(){
        public static void main(String[] args){
             mymath mm = new mymath( );
             mm.mysum(new compute(){				//此处就是匿名内部类,原本需要传入一个接口的实现类, 				
                  public int sum (int x, int y )  return x+y ;		//我们new接口,重写方法就行!,也就是实现类匿名了!
             },100 , 200 );
        }
    }
    

    七、数组

    一种引用数据类型,父类是Object,存放数据的容器,存储在堆内存当中

    1. 数组长度一旦定义,不可改变!

    2. 数组的内存地址,就是数组内第一个元素的内存地址

    3. int a[ ] ,a存储的就是数组a[ ]的首要内存地址,数组的内存地址是连续的!a + 1 = a[1] ;

      数组的JVM内存图:

    优点 :

    • 我们知道数组的第一个元素的内存地址,数组的内存地址又是连续的,我们可以通过偏移量,再通过字节大小推算出后面所有的内存地址精准定位,查询时间复杂度O(1) ;

    缺点:

    • 为了保证数组的内存地址连续,随机增删数组元素的时候(最后一个元素除外),效率较低,时间复杂度位O(n)!
    • 数组不能存储大数据量数据,因为很难找到一块大量的连续的数据空间

    语法格式 :

    静态初始化:int array[] = {1 , 2 , 3 , 4 , 5 }

    动态初始化:int array = new int [5] ; 此处的是指数组长度为5,每个元素默认值为 0 ;

    public static void main(String[] args) { } //String[ ] args 字符串数组有什么用?
    
    //JVM加载main方法的时候,会自动传入一个数组过来!
    
    System.out.println(args.length())  //输出0 ,表示长度为0的数组,已创建对象,但是数组里没有东西!
    

    1、数组扩容

    扩容机制:创建一个大数组,将小数组的数据一个一个Copy过来!

    结论:数组扩容效率较低,因为存在数组拷贝,所以在开发的时候注意:开辟数组的时候空间尽量把握准确!

    2、数组拷贝

    System类的静态方法arraycopy,会调用底层的C++程序,完成拷贝!

        public static native void arraycopy(Object src,  int  srcPos,
                                            Object dest, int destPos,
                                            int length);				//数组拷贝函数,需要传入5个参数
    
    //源数组、源数组开始下标、目标数组、目标数组开始下标、拷贝的数组长度!
    

    数组长度一旦确定不可改变,若需要增加长度,只能创建一个大数组,然后进行数组拷贝

    3、二维数组

    特殊的一维数组,一维数组当中的每个元素是一个一维数组 !

    静态初始化 : int [][] [ ] [ ] array = {{1,2,3,4} , {1,24,5} , {2,3,4,2,3,4} } //相当于3个一维数组!

    length 属性 :

    • array.length == 3 ;
    • array[0].length == 4 ;

    遍历二维数组:

    //遍历二维数组
            String[][] array = {
                    {"张三","李四","王五"},
                    {"Java","C++","C","C#"},
                    {"RabbitMQ","RocketMQ","kafka","Redis"},
                    {"Hadoop","Hive","Hbase","Zookeeper"}
            };
            for(int i = 0 ; i < array.length ; i ++ ){
                for (int j = 0; j < array[i].length ; j ++){
                    System.out.println(array[i][j]);
                }
                System.out.println("\n");
            }
    

    4、数组模拟栈

    public class ArrayStack {
        public static void main(String[] args) {
            int[] stack = new int[1001] ;
            int top = 0 ;
            //入栈
            int x ;
            Scanner scanner = new Scanner(System.in);
            x = scanner.nextInt() ;
            stack[++top] = x ;
            //出栈
            top -- ;
            //判断栈是否为空
            if (top > 0) System.out.println("not empty" );
            else System.out.println("empty");
            //求栈顶元素
            int res = stack[top];
        }
    }
    

    八、String 类

    一种引用数据类型,不属于基本数据类型,存储在方法区中的字符串常量池当中!

    特点:

    • 凡是 “ ” 括起来的都是String类型对象,都在字符串常量池中有一份,且“ ”中的内容是不可变的 !
    • 字符串间使用 + 是字符串连接操作符号 “abc” + “def” ===> “abcdef”
    • 垃圾回收器是不会释放,字符串常量池中的东西的!
    • String类已经重写了equals方法,字符串比较用equals()!

    一段代码对应的JVM:

    public class StringJVM {
        public static void main(String[] args) {
            String str = "abc" ;
            String str2 = "abc"  + "def" ;
            String str3 = new String("xy") ;
        }
    }
    //现在堆内存中创建空间,“xy”在常量池开辟空间,这样堆内存保存的就是常量池的地址!
    

    测试:以下代码创建了几个对象 ?

    public class StringJVM {
        public static void main(String[] args) {			//一共创建三个对象,2个在堆内存,一个在方法区的字符串常量池!
          	String str1 = new String("xy") ;
            String str2 = new String("xy") ;
        }
    }	
    -----------------------------------------------------------------------------------------------------------
    测试内存: 	
        String s1 = "abc" ;    //s1、s2 保存的是常量池中的地址
            String s2 = "abc" ;
            String s3 = new String("abc") ;  // s3、s4 保存的是堆内存中的地址
            String s4 = new String("abc") ;
     
            if (s1 == s2){
                System.out.println("内存地址相等");
            }
            System.out.println("-----------------------------------");
            if (s3 == s4){
                System.out.println("内存地址相等");
            }else{
                System.out.println("内存地址不等");
            }
    测试结果:
        
    内存地址相等
    -----------------------------------
    内存地址不等
    

    1、构造方法

    • String(byte[] bytes) :传入Byte数组,会通过默认的Ascii码来转化!
    • String(byte[] bytes, int offset, int length): 传入Byte数组,offset数组起始下标、length截取的长度
    • String(char[] value) :传入char数组,将char数组转化为String
    • String str3 = new String("xy") ; //初始化字符串

    2、String类的常用方法

    1、charAt方法

    //charAt方法、将通过下标获取字符串中,对象下标的字符!
     String name = "宋淇祥" ;
     char c = "宋淇祥".charAt(1);		
     System.out.println(c);      //淇
    

    2、compareTo方法

    //按照字典序比较字符串
        System.out.println("abc".compareTo("abc"));  //0 , 表示两个字符串字典序相等
        System.out.println("abcd".compareTo("abce")); //-1 ,abcd的字典序小于abce
        System.out.println("abce".compareTo("abcd")); // 1 ,abce的字典序大于abcd
    

    3、contains方法

    //contains方法
        System.out.println("12345678".contains("123"));  //true
        System.out.println("12".contains("123"));       //false
    

    4、endwith方法

    //endwith方法 bool类型
    System.out.println("123456".endsWith("456"));  //123456是否是以456为结尾的?true
    

    5、equals方法【掌握】

    重写equals方法,比较的是内容,不重写比较的是内存地址,String已经重写过equals了默认比较字符串内容

    == 比较的是内存地址!

    //equals方法,重写的Object的方法!
     System.out.println("123".equals("123"));   //true
    //重写后为:
     public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;	
                int n = value.length;
                if (n == anotherString.value.length) {	//字符串长度一致、长度将字符串转化为字符数组
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {			
                        if (v1[i] != v2[i])		//2个字符数组中的元素逐个匹配
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    
    

    6、equalsIgnoreCase方法

    判断两个字符串是否相等、忽略大小写

    //equalsIgnoreCase
    System.out.println("abc".equalsIgnoreCase("ABC"));   //true
    

    7、getBytes 方法

    将字符串转化为byte数组

    //getBytes()
        byte[] bytes = "abc".getBytes();
          for (byte b : bytes) {
              System.out.print(b+" ");	//97 98 99 
        }
    

    8、indexOf方法

    //indexOf方法,返回的是123在字符串中第一次出现的索引(下标)
    System.out.println("21234561123".indexOf("123"));  // 1
    

    9、isEmpty方法

    //isEmpty()  bool ,判断字符串是否为null,注意:" "并不是空串!
    System.out.println("".isEmpty()); //true
    
    //求数组长度,length属性
            System.out.println("123".length());
    //求字符串长度,length()方法
      		int[] a = {1,2,3};
            System.out.println(a.length);
    

    10、replace方法

    字符串替换

      //字符串替换
            String replace = "dadsadadsada====dasdasda===".replace("=", "+");  //将字符串中的=全部替换为+
            System.out.println(replace);	//dadsadadsada++++dasdasda+++
    

    11、split方法 【掌握】

    字符串拆分

     //字符串拆分,返回字符数组
     String[] ymd = "qwert=asdffg=zzzcxc".split("=") ; //字符串用=拆分为3个字符串
       for (String s : ymd) {
           System.out.print(s+ " ");   //qwert asdffg zzzcxc 
     }
    

    12、subString方法 【掌握】

    字符串截取

     System.out.println("qwert=asdffg=zzzcxc".substring(1, 5)); //wert  [开始下标,结束下标),前闭后开
    

    13、toLowerCase方法

    字符串全部转换为小写,大写为Upper

    System.out.println("ADASDASDASD".toLowerCase()); //adasdasdasd
    

    14、trim方法

    去除字符串中的空格

    System.out.println(" dsa sda sgg s ".trim());//dsa sda sgg s  去除的仅仅是字符串前后的空格
    

    15、valueOf方法 【掌握】

    String中唯一的静态方法,类名.直接调用String.valueOf()

    System.out.println(String.valueOf(true));   //将非字符串转化为字符串! "true"
    System.out.println(String.valueOf(3.14));
    
    //println方法底层调用String.valueOf方法,只有这样才能调用toString方法!
    //能打印在控制台上的都是字符串!
    

    3、StringBuffer

    为了解决字符串频繁使用+拼接,创建多个对象,浪费空间!

    本质:字符数组 (字符串缓冲区)

    StringBuffer extends AbstractStringBuilder
    //构造方法!
    public StringBuffer() {
            super(16); 			//本质:长度为16的char类型数组,满了之后数组自动扩容为之前的二倍!
     }
    //父类构造方法!
    AbstractStringBuilder(int capacity) {
          value = new char[capacity];
      }
    
    如何对StringBuffer优化?
        //初始化StringBuffer时候给一个合适的初始化容量,减少数组拷贝次数
    	StringBuffer stringBuffer = new StringBuffer(100);
    

    4、StringBuilder

    使用方法:与StringBuffer一致!

    区别:

    • StringBuffer都由synchronized修饰,是线程安全的 !
    • StringBuilder无synchronized修饰,非线程安全的 !

    九、八种包装类型

    为了方便开发而出现的一种机制!

    基本数据类型包装数据类型包装类的父类
    shortjava.lang.Shortjava.lang.Number
    bytejava.lang.Bytejava.lang.Number
    intjava.lang.Integerjava.lang.Number
    longjava.lang.Longjava.lang.Number
    booleanjava.lang.Booleanjava.lang.Object
    charjava.lang.Characterjava.lang.Object
    floatjava.lang.Floatjava.lang.Number
    doublejava.lang.Doublejava.lang.Number

    注意:重点学习java.lang.Integer即可,其余参照!

    装箱:将基本数据类型转化为引用数据类型

        Integer i = new Integer(100);  //装箱
    

    拆箱:将引用数据类型转化为基本数据类型

    由于包装类的父类是Number所以会继承Number中的所有方法:

        int i2 =  i.intValue();		   //拆箱	
    
        System.out.println(Integer.MAX_VALUE);   //获取int的最大取值范围 2147483647
        System.out.println(Integer.MIN_VALUE);	 //获取int的最小取值范围 -2147483648
    

    1、自动装箱自动拆箱

    JDK1.5引入了自动了自动装箱,和自动拆箱的概念,以后Number的方法就用不到了!

      Integer i = new Integer(100);
      int i2 =  i.intValue();     
    //自动化!
      int x = i ;
      Integer x2 = i2 ;
           
      System.out.println(x2 + 1); //此处遇到+运算符,自动拆箱!
    

    2、Integer的JVM分析

    Java中为了提高程序的执行效率,将[-128,127]之间的所有包装对象提前创建好,

    放到了一个方法去内存中的一个整型常量池当中,使得这个区间的对象不需要再new了!

      Integer a =  127 , Integer b =  127;
      System.out.println(a == b);   //true	;
    
      Integer a1 = 128 , Integer b1 = 128 ;
      System.out.println(a1 == b1);	//false ;
    
    注意: == 比较的是内存地址!
        
     Integer重写了equals方法,比较的是内容  
                public boolean equals(Object obj) {
                if (obj instanceof Integer) {
                    return value == ((Integer)obj).intValue();
                }
                return false;
            }
    
    

    扩展:当我们Integer类被加载的时候,内部的静态代码块也会执行,创建【-128—127】这256个对象,放入整型常量池的当中


    【-128—127】

    Integer重点方法:

    static int parseInt ( String s ){ } 静态方法:传入String,返回int(但是,只能将整数型字符串转化为int)

    static double parseInt ( String s ){ } 静态方法:传入String,返回double(只能将浮点型型字符串转化为double)

    多种类型转换:

    十、异常

    程序执行过程中,不正常的情况 ! 异常机制的作用:增强程序的健壮性

    异常是以类的形式存在的,new异常对象 注意:所有的异常都是发生在运行阶段

    异常继承结构图:

    、

    编译时异常和运行时异常区别:

    • 编译时异常:这种异常出现的概率较高,需要再编码阶段进行预处理
    • 运行时异常:发生的概率较低,并不需要预处理

    1、异常处理

    方式一:throw 【异常上抛】

    如果上抛到main中,仍然没有处理,就会抛给JVM,然后程序停止!

    package com.sqx;
    
    public class ExceptionTest01 {
        public static void main(String[] args) {
            try {
                doSome();	//预处理编译时异常, 
            } catch (ClassNotFoundException e) {
                e.printStackTrace();	
            }
        }
        public static void doSome() throws ClassNotFoundException{   //上抛编译时异常,调用的时候需要预处理
    
        }
    }
    //编译时异常必须进行预处理!
    

    类似于推卸责任!

    方式二:try catch 【异常处理】

    结合实际案例理解!

    public class ExceptionTest01 {
        public static void main(String[] args) {
            try {
                doSome();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        public static void doSome() throws FileNotFoundException {
            
            FileInputStream inputStream = new FileInputStream("");   //此处如果路径错误会异常向上抛出给main方法处理!   
        }
    }
    

    FileInputStream构造方法!

    、

    捕捉就是解决问题!

    2、异常常用方法

    1、e.printStackTrace();  //打印异常的堆栈信息
    2String str = e. getMessage() ;
    

    3、finally子句

    finally子句中的代码是最后且一定会执行的,且需要try catch一起出现!

    完整的异常处理流程!

    、

    需要注意的是:try和finally可以单独联用,使用步骤如下!

    、

    总结:放在finally语句块中的代码是一定会执行的!

    4、自定义异常

    //自定义编译时异常 , throw抛出该异常时,需要编译预处理!
    public class MyException extends Exception {
        public MyException() {
        }
    
        public MyException(String message) {
            super(message);			//含有编译时异常的所有特征!
        }
    }
    //自定义运行时异常
    public class MyRunException extends RuntimeException{
        public MyRunException() {
        }
    
        public MyRunException(String message) {
            super(message);
        }
    }
    

    分析:java.util包工具类

    1、java.util.Array

    • Array.sort( Object[ ] a ) : 将数组从小到大排序

    • Array.BinarySearch(Object [] a , int x) : 二分法查找 x ,返回的是下标,查不到返回 - 1!

    2、java.util.Date

    日期工具类

    详情如下:

    		Date date = new Date();
            System.out.println(date);       //Fri Sep 10 19:05:35 CST 2021
            //格式化时间
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String s = dateFormat.format(date);     //Date转换为字符串    2021-09-10 21:12:55 533
            System.out.println(s);
    
            //将日期字符串转换为Date类型
            String time  = "2000-07-10 20:59:42" ;
            SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date1 = dateFormat1.parse(time);   // Mon Jul 10 20:59:42 CST 2000
            System.out.println(date1);
    
            //获取从1970年到当前时间的总毫秒数
            long timeMillis = System.currentTimeMillis();       //1631279575568
            System.out.println(timeMillis);
    
            //构建Date对象传入毫秒数
            Date date2 = new Date(1);
            SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String s1 = dateFormat2.format(date2);  //  1970-01-01 08:00:00 001 北京时间、东八区
            System.out.println(s1);
    

    扩展:数字格式DecimalFormate

    3、java.util.Random

    生成随机数!

    public class RandomTest {
        public static void main(String[] args) {
            Random random = new Random();
            int num01 = random.nextInt();  //i是一个随机的int类型数据
            int num02 = random.nextInt(101); //在[0,101)的区间内产生一个int类型的数据
    
            //例题:生成5个不同的随机数,并且保存在数组当中
            int[] arr = new int[5];
            for (int i = 0; i < arr.length ; i++) {
                arr[i] = -1 ;
            }
            //循环生成随机数
            int index = 0 ;
            while(index < arr.length){
                int num = random.nextInt() ;
                if (!isContains(arr,num)){
                    arr[index++] = num ;
                }
            }
    
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]+" ");
            }
        }
    
        public static boolean isContains(int[] arr, int val){   //查询方法!
            for (int i = 0 ; i < arr.length ; i++) {
                if (arr[i] == val) return true ;
            }
            return false ;
        }
    }
    
    

    分析:java.lang包常用类

    1、java.lang.System

    简单总结一下System类的相关属性和方法!

    System.out ; //	out是System的静态变量
    System.out.println(); //	println()不是System类的,而是printStream类的方法!
    System.gc();	//建议启动垃圾回收器
    System.currentTimeMillis();	//获取从1970年到当前时间的总毫秒数
    

    2、java.lang.Object

    编译器(javac.exe)自动导入java.lang包,原因:因为用得多,提前加载了该包文件,且节省了资源。

    Object类下存在如下方法!

    • toString( ) 方法 :

      作用:将Java对象转化为字符串的形式

      //JDK中toString方法的源代码!    
      	public String toString() {
              return getClass().getName() + "@" + Integer.toHexString(hashCode());
                //类名 + @ + 将内存地址转化为16进制
          }
      

      当我们System.out.println(引用) == System.out.println(引用.toString ( ) ),这个println方法会自动调用这个引用toString方法!

      如果不满意输出的对象信息,我们可以重写toString方法,输出想要的对象信息!

    • equals( ) 方法:

      作用:比较具体的对象内容,如果内容一直,判断两个对象相等

      //默认情况Object的equals方法比较的还是两个对象内存地址,所以我们需要重写equals方法,使得比较的是对象的内容
      public boolean equals(Object obj){
          return this == obj ;  
      }
      
      //注意: "=="比较的是变量的字面值! 重写equals方法比较对象内容是否相同!
      //String 类型属引用数据类型,存在构造,只能用equals方法,并且String类已经重写了equals方法和toString方法,可以直接用!
      

      结论: Java中基本数据类型使用 ” == “ 判断是否相等

      ​ Java中引用数据类型需要使用 equals()方法判断是否相等!

    • finalize()方法:

      类似于遗言!,但是此方法于JDK9已经过时!

      protected void finalize () throws Throwable { }   //这个方法不需要程序员手动调用!JVM的GC机制会自动调用;
      
      //对内存中的对象,一般没有被引用,就会被回收!
      //如果希望对象销毁时机,执行一段代码,这段代码就可以写在finalize方法中!
      System.gc()  //建议JVM启动垃圾回收器,但是不一定启动!
      

      提示:Java中的垃圾回收器(GC)不是随时启动的,垃圾少可能不启动,有很多影响因素!

    • hashcode( ) 方法:

      将对象在堆内存的地址转化为等价的一串数字!

      public native int hashCode()   //不是抽象方法,带有native关键字是会调用底层的C++代码!
          
      //就是将java对象在堆内存中的地址,通过hash算法转换的一个数字,同样可以看作一个内存地址! 
      

    dateFormat2.format(date2); // 1970-01-01 08:00:00 001 北京时间、东八区
    System.out.println(s1);

    
    扩展:数字格式DecimalFormate
    
    
    
    ### 3、java.util.Random
    
    > 生成随机数!
    
    ```java
    public class RandomTest {
        public static void main(String[] args) {
            Random random = new Random();
            int num01 = random.nextInt();  //i是一个随机的int类型数据
            int num02 = random.nextInt(101); //在[0,101)的区间内产生一个int类型的数据
    
            //例题:生成5个不同的随机数,并且保存在数组当中
            int[] arr = new int[5];
            for (int i = 0; i < arr.length ; i++) {
                arr[i] = -1 ;
            }
            //循环生成随机数
            int index = 0 ;
            while(index < arr.length){
                int num = random.nextInt() ;
                if (!isContains(arr,num)){
                    arr[index++] = num ;
                }
            }
    
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]+" ");
            }
        }
    
        public static boolean isContains(int[] arr, int val){   //查询方法!
            for (int i = 0 ; i < arr.length ; i++) {
                if (arr[i] == val) return true ;
            }
            return false ;
        }
    }
    
    

    分析:java.lang包常用类

    1、java.lang.System

    简单总结一下System类的相关属性和方法!

    System.out ; //	out是System的静态变量
    System.out.println(); //	println()不是System类的,而是printStream类的方法!
    System.gc();	//建议启动垃圾回收器
    System.currentTimeMillis();	//获取从1970年到当前时间的总毫秒数
    

    2、java.lang.Object

    编译器(javac.exe)自动导入java.lang包,原因:因为用得多,提前加载了该包文件,且节省了资源。

    Object类下存在如下方法!

    • toString( ) 方法 :

      作用:将Java对象转化为字符串的形式

      //JDK中toString方法的源代码!    
      	public String toString() {
              return getClass().getName() + "@" + Integer.toHexString(hashCode());
                //类名 + @ + 将内存地址转化为16进制
          }
      

      当我们System.out.println(引用) == System.out.println(引用.toString ( ) ),这个println方法会自动调用这个引用toString方法!

      如果不满意输出的对象信息,我们可以重写toString方法,输出想要的对象信息!

    • equals( ) 方法:

      作用:比较具体的对象内容,如果内容一直,判断两个对象相等

      //默认情况Object的equals方法比较的还是两个对象内存地址,所以我们需要重写equals方法,使得比较的是对象的内容
      public boolean equals(Object obj){
          return this == obj ;  
      }
      
      //注意: "=="比较的是变量的字面值! 重写equals方法比较对象内容是否相同!
      //String 类型属引用数据类型,存在构造,只能用equals方法,并且String类已经重写了equals方法和toString方法,可以直接用!
      

      结论: Java中基本数据类型使用 ” == “ 判断是否相等

      ​ Java中引用数据类型需要使用 equals()方法判断是否相等!

    • finalize()方法:

      类似于遗言!,但是此方法于JDK9已经过时!

      protected void finalize () throws Throwable { }   //这个方法不需要程序员手动调用!JVM的GC机制会自动调用;
      
      //对内存中的对象,一般没有被引用,就会被回收!
      //如果希望对象销毁时机,执行一段代码,这段代码就可以写在finalize方法中!
      System.gc()  //建议JVM启动垃圾回收器,但是不一定启动!
      

      提示:Java中的垃圾回收器(GC)不是随时启动的,垃圾少可能不启动,有很多影响因素!

    • hashcode( ) 方法:

      将对象在堆内存的地址转化为等价的一串数字!

      public native int hashCode()   //不是抽象方法,带有native关键字是会调用底层的C++代码!
          
      //就是将java对象在堆内存中的地址,通过hash算法转换的一个数字,同样可以看作一个内存地址! 
      
  • 相关阅读:
    Ural 1057. Amount of Degrees
    BZOJ 3517: 翻硬币
    BZOJ 4527: K-D-Sequence
    CTC联结时间分类算法(语音、文本识别)
    我小苏太狼又回来了.
    /*--------------分割线--------------*/
    /*--------------分割线--------------*/
    洛谷 P4149 [IOI2011]Race-树分治(点分治,不容斥版)+读入挂-树上求一条路径,权值和等于 K,且边的数量最小
    Codeforces 161.D. Distance in Tree-树分治(点分治,不容斥版)-树上距离为K的点对数量-蜜汁TLE (VK Cup 2012 Round 1)
    洛谷 P2634 [国家集训队]聪聪可可-树分治(点分治,容斥版) +读入挂+手动O2优化吸点氧才过。。。-树上路径为3的倍数的路径数量
  • 原文地址:https://www.cnblogs.com/qxsong/p/15837296.html
Copyright © 2020-2023  润新知