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算法转换的一个数字,同样可以看作一个内存地址! 
    
posted @ 2022-01-23 20:36  爪洼ing  阅读(136)  评论(0编辑  收藏  举报