Java 基础知识(复习专用)

目录

Java的优点

开源、可移植、多线程、面向对象和高性能等特性

专业用语介绍

源文件

程序员一行一行进行编写可以读得懂的程序文件,能够根据再次修改的文件,能够在硬盘上存放很久的文件。它的后缀名是.java。

编译后文件

编译器进行检查后生成的字节码文件,它是Java虚拟机能够读的懂的文件。

JVM(java虚拟机)

它是Java所运行的环境,它屏蔽了操作系统的具体指令,提供Java语言运行所能操作相关指令。

JDK

Java Development Kit(Java开发工具包)

JRE

Java Runtime Environment(Java运行时环境)

Java自带包

在这里插入图片描述

main函数的作用

主函数main()是Java虚拟机(JVM)调用程序的入口函数。JVM只认识这个入口函数。
一个程序会有多个类,但是只需要有一个类有入口函数(main)就够了。

JAVA关键字

关键字一律用小写字母标识,按其用途划分为如下几组。
(1)数据类型
  用于数据类型的关键字有 boolean、byte、char、 double、 false、float、int、long、new、short、true、void、instanceof。
  
(2)语句
  用于语句的关键字有break、case、 catch、 continue、 default 、do、 else、 for、 if、return、switch、try、 while、 finally、 throw、this、 super。
  
(3)修饰
  用于修饰的关键字有 abstract、final、native、private、 protected、public、static、synchronized、transient、 volatile。
  
(4)方法、类、接口、包和异常
  用于方法、类、接口、包和异常的关键字有 class、 extends、 implements、interface、 package、import、throws。
  
  还有些关键字,如cat、 future、 generic、innerr、 operator、 outer、rest、var等都是Java保留的没有意义的关键字。
  
  另外,Java还有3个保留字:true、false、null。它们不是关键字,而是文字。包含Java定义的值。和关键字一样,它们也不可以作为标识符使用。
  
关键字解释
abstract
表明类或者成员方法具有抽象属性

assert
断言,用来进行程序调试

boolean
基本数据类型之一,声明布尔类型的关键字

break
提前跳出一个块

byte
基本数据类型之一,字节类型

case
用在switch语句之中,表示其中的一个分支

catch
用在异常处理中,用来捕捉异常

char
基本数据类型之一,字符类型

class
声明一个类

const
保留关键字,没有具体含义

continue
回到一个块的开始处

default
默认,例如,用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现

do
用在do-while循环结构中

double
基本数据类型之一,双精度浮点数类型

else
用在条件语句中,表明当条件不成立时的分支

enum
枚举

extends
表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口

final
用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量

finally
用于处理异常情况,用来声明一个基本肯定会被执行到的语句块

float
基本数据类型之一,单精度浮点数类型

for
一种循环结构的引导词

goto
保留关键字,没有具体含义

if
条件语句的引导词

implements
表明一个类实现了给定的接口

import
表明要访问指定的类或包

instanceof
用来测试一个对象是否是指定类型的实例对象

int
基本数据类型之一,整数类型

interface
接口

long
基本数据类型之一,长整数类型

native
用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的

new
用来创建新实例对象

package

private
一种访问控制方式:私用模式

protected
一种访问控制方式:保护模式

public
一种访问控制方式:共用模式

return
从成员方法中返回数据

short
基本数据类型之一,短整数类型

static
表明具有静态属性

strictfp
用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范

super
表明当前对象的父类型的引用或者父类型的构造方法

switch
分支语句结构的引导词

synchronized
表明一段代码需要同步执行

this
指向当前实例对象的引用

throw
抛出一个异常

throws
声明在当前定义的成员方法中所有需要抛出的异常

transient
声明不用序列化的成员域

try
尝试一个可能抛出异常的程序块

void
声明当前成员方法没有返回值

volatile
表明两个或者多个变量必须同步地发生变化

while
用在循环结构中

java垃圾回收机制

如何确定哪些内存需要回收?有两种算法:引用计数法和可达性分析法,目前虚拟机基本都采用了可达性分析法, 简单了解下两种算法:

引用计数法

给对象添加一个引用计数器,每当有一个地方引用它的地方,计数器值+1;当引用失效,计数器值就减1;任何时候计数器为0,对象就不可能再被引用了。

虚拟机为什么不使用这种算法呢?因为它无法解决对象互相引用的情况:
在这里插入图片描述

可达性分析法

这个算法的基本思想是通过一系列称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的。

在这里插入图片描述

JVM内存模型

GC回收的是堆上的内存,除了堆,JVM中还有什么呢?了解下JVM的内存模型。

JVM虚拟机有不同种,现在我们用的JVM大多数情况下都是在安装JDK时绑定安装的,而目前JDK中的JVM使用的是HotSpot虚拟机,我们学习和研究的基本上也都是这种虚拟机的内存模型。

JVM分为了几个部分:
在这里插入图片描述

我们再来看看堆(Heap)

堆是JVM内存占用最大,管理最复杂的一个区域。其唯一的用途就是存放对象实例:所有的对象实例及数组都在对上进行分配。JDK1.8中常量池(包括字符串常量)、静态变量从永久代中剥离出来,存放在堆中。

在这里插入图片描述

堆有自己进一步的内存分块划分,默认情况下按照GC分代收集角度的划分如下图:

在这里插入图片描述

垃圾收集算法

垃圾收集算法有:标记-清除法、复制法、标记-整理法。

标记-清除法(Mark-Sweep):

分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,标记完成后统一回收所有被标记的对象。这种算法的不足主要体现在效率和空间上。

在这里插入图片描述

复制法(Copying):

它将可用的内存分为两块,每次只用其中一块,当这一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已经使用过的内存空间一次性清理掉。这种算法有个缺点,内存缩小为了原来的一半,这样代价太高了,现在的商用虚拟机都采用这种算法来回收新生代,不过研究表明1:1的比例非常不科学,因此新生代的内存被划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。HotSpot虚拟机默认Eden区和Survivor区的比例为8:1:1,意思是每次新生代中可用内存空间为整个新生代容量的90%。

在这里插入图片描述

标记-整理法:

不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉边界以外的内存。

在这里插入图片描述

  		/*
        关于垃圾回收机制(garbage collection 简称gc)
        什么叫垃圾?
            (1)无用信息对象
            (2)无用对象
             总结来说,就是没有引用的对象叫垃圾,例子如下
         */
         
        //这个对象没有变量引用它,很快会被回收
        new Integer(2);
        
        //下方的变量a指向右边的对象(integer)
        Integer a = new Integer(1);
        
        //我把a指向了null,那么integer就没有对象去指向它,可以说integer没有任何作用了(沉入海底,找不到这个对象榈)。
        a = null;
        
        //a指向了另一个对象,相当于new Integer(1)被抛弃,很快就会被回收。
        a=new Integer(3);
        
        /*
        当我提醒系统,你该去清理垃圾了的时候。
        注意这个地方,我提醒系统该去清理垃圾,而不是让他去清理垃圾。
        系统有自己的算法判断当前是否需要清理垃圾。
        你提醒他,他只会执行算法判断当前是否需要清理垃圾,而不是直接清理垃圾。
        而且回收对象之前,会先执行对象的finalized方法
         */
        
        //提醒系统,清理垃圾。
        System.gc();

注释(代码千万行,注释第一行)

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

标识符命名规则(代码不规范,迟早要滚蛋)

建议只使用字母、数字、下划线组成标识符。
在这里插入图片描述

数据类型

在Java中数据类型可以分为两大类:基本数据类型和引用数据类型。

基本类型是不能简化的、内置的数据类型,由编程语言本身定义。引用类型则复杂一些,一般通过类和接口进行构造。另外,基本类型不存在“引用”的概念,基本类型的变量中存储的就是数据值本身,而引用类型则不然,引用类型中存储的值并非数据本身,而是真实对象在内存中实际存储位置的一种关联,通过这个关联,引用类型的变量能够引用实际的对象,这也就是“引用”的由来。

基本类型存储数值,引用类型存储地址。(引用类型可以类比C语言的指针去进行理解。)

基本类型

Java基本类型共有八种

1.四种整数类型(byte、short、int、long):

byte:8位、有符号。最小值是 -128(-2^7)、最大值是 127(2^7-1)、默认值是 0;

byte a = 100

short:16位、有符号。最小值是 -32768(-2^15)、最大值是 32767(2^15 - 1)、默认值是 0;

short s = 1000

int:32位、有符号。最小值是 -2,147,483,648(-2^31)、最大值是 2,147,483,647(2^31 - 1)、默认值是 0;

int n =100000

long:64位、有符号。最小值是 -9,223,372,036,854,775,808(-2^63)、最大值是 9,223,372,036,854,775,807(2^63 -1)、默认值是 0L;

long a = 100000L

2.两种浮点数类型(float、double):

float:单精度、32位。默认值是 0.0f;

float f = 234.5f

double:双精度、64位。浮点数的默认类型为double类型、默认值是 0.0d;

double d1 = 123.4

3.一种字符类型(char):

char:16位。最小值是 \u0000(即为0)、最大值是 \uffff(即为65,535)、char 数据类型可以储存任何字符;

char letter = 'A'

4.一种布尔类型(boolean):

true 真 和 false 假 。默认值是 false;

boolean flg = true

上述知识参考文章
在这里插入图片描述
基本类型的转换:
小容量转大容量:500ml瓶子中的水倒入800ml的瓶子中,水量丝毫没有影响。
大容量转小容量:800ml瓶子中的水倒入500ml的瓶子中,水量可能会因为溢出而减少。(所谓精度受损)
因为大转小有风险,所以需要人为的去强制转换。
例如:

		int big = 123456;
        short small = 0;
        //强制转换
        small = (short) big;
        System.out.println(small);

在这里插入图片描述

变量

能够精确的向程序描述确切需要引用“数据”,这种描述所用的代号,称为变量。

通俗一点来说,变量的作用就是方便运算。

常量

变量的值在程序运行过程中可能会发生变化,有些数据的值则在程序运行过程中不能发生改变,这样的数据我们称之为常量
例如

//final 代表最终的,不可改变的,正好满足常量的定义。
final double PI = 3.14159

控制台的输入和输出

print(输出)

 System.out.println("我是一个控制台输出");

scanner(输入)

		//创建控制台输入对象
        Scanner scanner = new Scanner(System.in);
        //接受控制台输入的int值
        int acceptInt = scanner.nextInt();
        //接受控制台输入的string值
        String acceptString = scanner.next();

运算符

算数运算符

	/*
    +   如果含有字符串  那么+就变成了拼接
    -   没有什么可说的
    *   也没有什么可说的
    /   如果除数和被除数都是整数  那么结果为整数  反之有一个数带小数  那么结果就带小数
     */
        int a = 3;
        int b = 4;
        float c = 1.5f;
        String d = "5";
        //整数的除
        System.out.println(a / b);
        //整数的取模
        System.out.println(a % b);
        //小数的除
        System.out.println(a / c);
        //小数的取模
        System.out.println(b % c);
        //字符串的加法
        System.out.println(d + a);
        //整数(小数)的先加加和后加加  减减和加加同理
        System.out.println(a++);
        System.out.println(++b);

在这里插入图片描述

赋值运算符

在这里插入图片描述

比较运算符

		// 大于等于的意思是:大于或者等于,二者成立一即为真  其他类似运算符也是同理
        System.out.println(3>=3);
package com.ives.three;

/*
   @about file:write here
   @author:Ives
   @time:2020/11/12 15:05
 */
public class DemoTwo {
    /*
    ability of this function:write here
    @param [args]
    @return void
    */
    public static void main(String[] args) {
        // instanceof  用来判断某个对象是否属于某个类
        displayObjectClass("123");
    }

    public static void displayObjectClass(Object o) {
        if (o instanceof String)
            System.out.println("对象是String类的实例");
        else if (o instanceof Integer)
            System.out.println("对象是Integer类的实例");
    }
}

在这里插入图片描述

逻辑运算符

在这里插入图片描述

 /*
       && 和&的区别

            &&的短路功能,当第一个表达式的值为false的时候,则不再计算第二个表达式;
            &则两个表达式都执行;

       |和||的区别

            ||的短路功能,当第一个表达式的值为true的时候,则不再计算第二个表达式;
            |则两个表达式都执行;
        */
        int a = 3;
        int b = 4;
        int c = 5;
        int d = 6;
        if (a > 3 & b++ > 4) {
        }
        System.out.println("b的值改变了,说明两个表达式都执行了");
        System.out.println(b);

        if (c > 5 && d++ > 6) {
        }
        System.out.println("d的值没变,说明了只执行了第一个表达式");
        System.out.println(d);

位运算符

int a = 3;
        int b = 4;
        

        /*
        ^ 异或的意思:二进制状态 相同则0 不同则1
          例如:
             10100001 ^ 00000110 = 10100111
        按位异或的3个特点:

            (1)0异或任何数 = 任何数;

            (2)1异或任何数 = 任何数取反;

            (3)任何数异或自己 = 把自己置0;
         */
        System.out.println(a ^ 1);
        System.out.println(a ^ 0);
        System.out.println(a ^ a);
        System.out.println(a & b);
        /*
        ~ 按位取反的意思是 二进制状态 0变1 1变0
         */
        System.out.println(~a);

        /*
        不要把这里的&和|与逻辑运算符中的&|搞混了
        这里的运算符接收的是值  逻辑运算符接收的是表达式
        & 按位与的意思是:二进制状态  全为1才为1
         */
        System.out.println(a & a);
        /*
        |按位或的意思是:二进制状态 全为0才为0
         */
        System.out.println(a | a);

在这里插入图片描述

条件运算符

  		/*
        条件运算符又叫三元运算符,主要格式如下
            表达式?true:false
         */

        //求三个数的最大值
        int a = 3;
        int b = 4;
        int c = 5;
        //如果a大于b 把a赋值给max  反之把b赋值给max
        int max = a > b ? a : b;
        //与上同理
        max = max > c ? max : c;
        //输出最大值
        System.out.println(max);

if语句

 		//定义分数
        int score=90;
        //如果分数大于等于90就判定为优秀
        if (score>90){
            System.out.println("优秀");
        }
        //如果分数小于60就叫家长
        else if (score<60){
            System.out.println("准备叫家长!");
        }
        //此外所有的分数都判定为良好
        else{
            System.out.println("良好");
        }

如果if判断条件的后面不加大括号,那么它的作用区域遇到第一个分号结束。

switch语句

/*
        1.关于case后面的break;
        如果case后不加break,会继续执行下一个case的代码;(可自行实验)
        2.关于switch支持的类型
        byte、short、int、char、string(1.7版本后才开始支持)
         */
        int day = 3;
        switch (day) {
            case 1:
                System.out.println("周一");
                break;
            case 2:
                System.out.println("周二");
                break;
            case 3:
                System.out.println("周三");
                break;
            case 4:
                System.out.println("周四");
                break;
            case 5:
                System.out.println("周五");
                break;
            case 6:
                System.out.println("周六");
                break;
            case 7:
                System.out.println("周日");
                break;
            default:
                System.out.println("错误");
                break;
        }

while语句

/*
        1.关于while的执行
        先判断条件,在执行代码段的内容
        2.关于do-while的执行
        先执行代码段,在判断条件,也就是说do-while最少执行代码段一次
        3.关于break的作用
        打破循环
        4.关于continue的作用
        结束本次执行,开始下一次执行
         */
        int i = 1;
        while (i < 10) {
            if (i == 4) {
                System.out.println("我不喜欢4这个数字,下一个!");
                i++;
                continue;
            }
            if (i == 5) {
                System.out.println("劳资不陪你玩了,再见!我要打破循环跑路去了!");
                break;
            }
            System.out.println(i++);
        }

        do {
            System.out.println("劳资就是这么任性,就算不满足条件,我也能执行一次");
        } while (i < 5);
    }

for语句

在这里插入图片描述

 /*
        1.关于for的三个表达式
        第一个表达式=="初始化"(最开始执行,且只执行一次)
        第二个表达式==循环判断条件(n次循环执行n+1次)
        第三个表达式==每次循环结束后执行(相当于在代码段的尾端书写 n次循环执行n次)
         */

        /*
        阶乘和连加的demo
         */
        int allMultiply = 1;
        int allAdd = 0;
        for (int i = 1; i < 10; i++) {
            allAdd += i;
            allMultiply *= i;
        }
        System.out.println("阶乘:" + allMultiply + "\t连加:" + allAdd);
    }

函数

public static void main(String[] args) {
        /*
        这里的dogName是实参
        函数参数的name是形参(只是走个形式,接受传输的参数值)
         */
        String dogName = "汪汪";
        printName(dogName);
    }

    /*
    函数的三个必要条件:函数名、参数列表、返回值类型。
    例如下方函数为例
        函数名	printName
        参数列表 String name
        返回值 void
     */
    public static void printName(String name) {
        System.out.println(name);
    }

在这里插入图片描述

参数为基本数据类型:值传递(传递的是值)
参数为引用数据类型:引用传递(传递的是地址)

函数重载

	//以下函数都是重载函数
    public void printName(String name) {
        System.out.println(name);
    }

    //和上方函数参数数量不同
    public int printName() {
        return 1;
    }

    //和下方函数参数顺序不同
    public void printName(String name, String sex) {
    }

    public void method(String sex, String name) {
    }

    //和上方函数参数类型不同  参数名无关轻重
    public void printName(int sex, String name) {
    }

在这里插入图片描述
上方图片中的参数列表说的不准确,应该为:参数类型,个数,顺序(和参数名没有关系)。而且和返回值没有任何关系。

数组

数组初始化

静态初始化

		/*
        数组静态初始化
        简化格式:
	    数据类型[] 数组名称 = {值, 值, …};
        完整格式(推荐):
	    数据类型[] 数组名称 = new 数据类型[]{值, 值, …};
	    数据类型可以是8种基本的数据类型,也可以是引用数据类型
         */

        //标识符结尾处的s代表这是一个数组,与变量进行区分
        int[] flowers = {1, 2, 3};
        //上方是简化版,下方是完整版
        int[] trees = new int[]{4, 5, 6};

动态初始化

		 /*
        数组动态初始化
        数组类型[] 数组名 = new 数据类型[数组长度];
        数据类型可以是8种基本的数据类型,也可以是引用数据类型。
        
        当数组采用动态初始化开辟空间之后,数组之中的每个元素都是该数据类型的默认值。
        具体的数组类型和对应默认值如下
            数据类型	                默认初始化
            byte、short、int、long	0
            float、double	        0.0
            char	                一个空字符,即 ‘\u0000’
            boolean	                false
            引用数据类型	            null,表示变量不引用任何对象

         */
        int[] dogs = new int[10];
        int[] cats = new int[10];

如何判别数组是静态初始化还是动态初始化?
有默认值就是动态初始化

数组遍历

		//迭代遍历  改变变量tree的值不会影响数组的值
        for (int tree : trees) {
            System.out.println(tree);
        }
        //下标遍历
        for (int i = 0; i < trees.length; i++) {
            System.out.println(trees[i]);
        }

数组的进阶使用

二分查找

		int[] trees = new int[]{4, 5, 6};
		//返回值为查找的值所在的数组下标,没找到该值就返回-1。
        int index = Arrays.binarySearch(trees, 4);
        System.out.println(index);

排序

int[] trees = new int[]{4, 5, 6, 3, 2, 1};
/* 这里的3、6是指数组排序的范围
	例如 排序的范围是数组下标为3到数组下标为5(6-1)
*/
Arrays.sort(trees,3,6);

Arrays.sort只帮我们升序排列,那我们如何解决降序排列或者其他排序问题,比如按照赵钱孙李排序呢?

package com.ives.four;

import java.util.Arrays;
import java.util.Comparator;

/*
   @about file:write here
   @author:Ives
   @time:2020/11/13 16:10
 */
public class DemoFour {
    public static void main(String[] args) {
        //注意这个地方  不是int  而是Integer
        Integer[] trees = {4, 5, 6, 3, 2, 1};

        //按照DownSort中的规则进行排序。
        Arrays.sort(trees, new DownSort());

        //数组遍历
        for (int tree : trees) {
            System.out.println(tree);
        }
    }
}

/*
下面的类你可以看作排序类,它的职责就是按照你的心意去排序数组。
建议把这个类单独建立一个.class文件,后期便于维护和查找。
 */
class DownSort implements Comparator<Integer> {
    @Override
    public int compare(Integer o1, Integer o2) {
        //降序写法  升序则相反  
        if (o1 < o2) {
            return 1;
        } else if (o1 > o2) {
            return -1;
        } else {
            return 0;
        }
    }
}

当然了,实现数组降序的方法不止一种,这里只说明和Arrays.sort有关的这种方法。

数组复制

		//数组初始化
        String[] students = new String[]{"小明", "小红", "小蓝"};

        //默认从下标为0开始复制  复制的长度为1
        String[] someHumans = Arrays.copyOf(students, 1);

        //数组遍历
        for (String array : someHumans) {
            System.out.println(array);
        }

        //加强版,有始有终型。复制范围从下标1到下标2(3-1)
        String[] someHumansTwo = Arrays.copyOfRange(students, 1, 3);

        //数组遍历
        for (String array : someHumansTwo) {
            System.out.println(array);

数组比较

/*
        two arrays are considered equal if both
        arrays contain the same number of elements,
        and all corresponding pairs
        of elements in the two arrays are equal.
        In other words, two arrays
        are equal if they contain the same elements
        in the same order.
        Also,two array references are considered equal
        if both are <tt>null</tt>.<p>
        综上所述,两个数组相等,那么包含相同的元素,且排列顺序也相同。
        如果两个数组都为null  那么它俩相等。
         */
        int[] nums = null;
        int[] nums2 = null;
        int[] nums3 = new int[]{1, 2, 3};
        int[] nums4 = new int[]{4, 5, 6};
        int[] nums5 = new int[]{5, 6, 4};
        int[] nums6 = new int[]{1, 2, 3};
        System.out.println(Arrays.equals(nums3, nums4));//false
        System.out.println(Arrays.equals(nums4, nums5));//false 虽然元素相等 但是顺序不同
        System.out.println(Arrays.equals(nums3, nums6));//true  元素相等 顺序相同
        System.out.println(Arrays.equals(nums, nums2));//true   两个null的数组相等

数组填充

//把nums3中的所有元素都变为9
int[] nums3 = new int[]{1, 2, 3};
Arrays.fill(nums3, 9);

数组转字符串

//把数组形式变为字符串形式
int[] nums = new int[]{1, 2, 3};
String allNum = Arrays.toString(nums);

字符串

在这里插入图片描述
还记得final的作用吗?final:最终的,不可改变的。所以String的值不可以修改。所谓修改String的值本质上是建立新的String进行重新赋值。
String作为一次性用品,资源浪费比较大,所以呢,产生了相关解决措施。
String作为常量,在不new的情况下,允许共享常量。例子如下

//你以为会占两个坑?通过比较a、b的堆内存地址发现,它们共享一个地址,是不是减少了资源花销。
String a = "我不能被修改";
String b = "我不能被修改";
/*
简单单说一下  ==的使用
使用在基本类型上,比较的是数值。
使用在引用类型上,比较的是内存中的地址(堆内存地址)
*/
System.out.println(a == b);

equals和==的区别

/*
        简单说一下  == 和equals的区别
            ==
                使用在基本类型上,比较的是数值。
                使用在引用类型上,比较的是内存中的地址(堆内存地址)
            equals
                object超类默认比较内存中的地址,但是很多子类重写了equals方法,
                例如String类,重写方法后equals:首先比较两个字符串的引用是否相同,如果相同则返回true,如果不相同,那么比较两个字符串每个位置对应的char值(字符串内容)是否相同,相同则返回True。
         */

字符串的常用方法

转换大小写

 		String word = "Luck";
        //把字母全转换成小写
        System.out.println(word.toLowerCase());
        //把字母全转换成大写
        System.out.println(word.toUpperCase());

去除首尾的空白数据

		String word = "   I am Ives   ";
        //去除字符串首尾的空白部分
        System.out.println(word.trim());

字符串的截取

 		String word = "你好,我叫小猪佩奇,我来自xxx";
        //截取字符串 从下标为0截取到下标为2
        System.out.println(word.substring(0, 2));

字符串长度

		//空格也算长度	
		String a="我是一只小小鸟  ";
		System.out.println(a.length());

字符串分裂成数组

		String a = "我是一只小小鸟,怎么飞也飞不高";
        //按照逗号进行分裂,返回的结果是一个数组
        String[] arrays = a.split(",");
        //遍历输出数组
        for (String array : arrays) {
            System.out.println(array);
        }

获取字符串的第n个字符

		String a = "我是一只小小鸟,怎么飞也飞不高";
		//输出字符串中index为0的字符
        System.out.println(a.charAt(0));

获取字符串中第n个字符的unicode值

  		String b = "a";
        //输出字符串中index为0的字符的unicode值
        System.out.println(b.codePointAt(0));

字符串比较

 		String b = "a";
        String c = "ABCD";
        //  按字典顺序比较两个字符串(默认比较第一个字符,如果相同就比较第二个字符)  大于0则大于  小于0则小于  等于0则等于
        System.out.println(b.compareTo(c));
        //比较字符串时忽略大小
        System.out.println(b.compareToIgnoreCase(c));

字符串拼接

		String e="哈哈哈";
        String f="你笑毛?";
        // 将指定字符串连接到此字符串的结尾。
        String g =e.concat(f);
        System.out.println(g);

判断字符串是否包含某个字符串(字符)

 		String h = "abcdefg";
        //当此字符串包含指定的 char 值序列时,返回 true。
        System.out.println(h.contains("a"));

判断字符串是否相等

		/*
        说一下equals和contentEquals的区别
            equals先比较两者的堆内存地址是否相同在比较字符串的内容是否相同
            contentEquals直接比较两者的字符串内容是否相等,不比较堆内存地址
         */
        System.out.println(g.equals(h));
        System.out.println(g.contentEquals(h));
         //比较时忽略大小写
        System.out.println(g.equalsIgnoreCase(h));

字符串的开头和结尾

		String h = "text.txt";
        //如果字符串以.txt结尾 那么返回true
        System.out.println(h.endsWith(".txt"));
        //如果字符串以xt开头,那么返回true,从index为2开始检测。默认为0,代表从头开始。
        System.out.println(h.startsWith("xt", 2));

字符串类型转字节类型

		String h="qwer你好";
        //使用utf-8的字符集将String转换成字节类型
        byte[] myByte = h.getBytes("utf-8");
        for (byte array : myByte) {
            System.out.println(array);
        }

字符串类型转字符类型

		String word = "luck";
        //把字符串转为字符
        char[] words = word.toCharArray();
        for (char array : words) {
            System.out.println(array);
        }

查找某个字符(字符串)在字符串中的位置

		String h = "钓鱼要到岛上钓,不到岛上钓不到";
        //从左到右查找且在index为7之后第一次出现岛的index
        System.out.println(h.indexOf("岛", 3));
        //从右到左查找查找index<=7的位置且第一次出现岛的index
        System.out.println(h.lastIndexOf("岛", 7));

替换字符串的某些内容

 		String some = "我的工号是12,我的工资是20000";
        /* replace和replaceAll、replaceFirst的区别
                replace只是替换具体的值,比如工号
                replaceAll替换的是抽象的值,比如数字,两位数,三位数等等。
                replaceFirst相对replaceAll而言,只替换匹配到的第一个值,后面的不替换。
         */
        System.out.println(some.replace("工号", "员工编码"));//我的员工编码是12,我的工资是20000
        //现在公司有规定,数字对外保密,数字应该变为星号。数字就是抽象的值,不是具体的指定的值。
        System.out.println(some.replaceAll("\\d+", "*"));//我的工号是*,我的工资是*
        //只替换第一个值
        System.out.println(some.replaceFirst("\\d+", "*"));

判断字符串是否为空

		String j = "";
        //如果字符串长度为0  那么就代表为空  则isEmpty为true
        System.out.println(j.isEmpty());

匹配字符串中的内容

涉及到正则表达式,比较复杂。
下面只作简单示例,如需进一步学习,请看另一篇详细文章。链接

		String website = "www.baidu.com";
        /*正则表达式:定义搜索模式的字符序列(个人理解:检索某些有共同特征的字符串)
        例如:下方的正则表达式的功能:检索所有www.xxxx.com的字符串,他们的共同的特征就是www.开头 .com结尾  中间是啥我不在乎
        ^代表开头 $代表结尾 .代表匹配所有可见字符
         */
        System.out.println(website.matches("^www\\..+\\.com$"));

String、StringBuffer、StringBuilder的关系

详细知识

常用算法

数组颠倒算法

 		//定义数组
        int[] arrays = new int[]{1, 2, 3, 4, 5};
        /*
        说一下数组颠倒的原理:首尾互换
            长度为奇数:中间的那个数不用换,首尾互换
            长度为偶数:首尾互换
            所以综上所得,奇数偶数不会影响。
            
            for循环进行,循环次数为数组长度的一半
            然后进行典型的两者互换值问题(建立第三个临时值帮助两个值互换)
         */
        for (int i = 0; i < arrays.length / 2; i++) {
            //建立临时值作为互换的工具
            int temp = arrays[i];
            arrays[i] = arrays[arrays.length - 1 - i];
            arrays[arrays.length - 1 - i] = temp;
        }

        //遍历输出
        for (int array : arrays) {
            System.out.println(array);
        }

查找算法

学习资源

排序算法

学习资源

面向对象编程(Object Oriented Programming)

为什么要学面向对象编程?
面向过程虽然可以快速的实现某个功能,但是对于后期需要的扩展性和维护性都无法保证。

三大特性

  • 封装(属性私有化,方法公开化):是类的一个重要的特征,它将数据和行为打包写在同一个类中。在对于使用这个类的其他程序来说会隐藏掉自己的具体实现方式。
  • 继承:面向对象运行在创建新的类时使用现有的类作为模板,进行扩充功能和改进实现。
  • 多态:按字面的意思就是多种形态。在面向对象语言中,我们可以将函数的形参定义为一个父类类型,而在真正调用该函数时这个父类类型的所有子类对象都可以传入,根据传入的子类对象不同,函数可以运行出多种形态。

优点

  • 封装性好
  • 易于维护
  • 易于扩展
  • 代码质量好

缺点

  • 特定的环境支撑
  • 具体的业务无法从高层次进行分析

类与对象

类是一类事物的抽象和概括,对象是其中一个具体的实例。
说一个程序猿的梗,帮你记忆类与对象

程序员没有对象怎么办?new一个啊。。。(哈哈哈哈)

构造函数(修饰符尽量为public)

虽然是个函数,但是函数名与类名相等,没有返回值。
任性的背后都是简单粗暴的实力,所以请你继续往下看,任性的构造函数是多么重要。

构造函数是对象的被初始化完成之后,将引用地址传递出去的唯一方法(出口),也就是说想要得到对象,必须通过构造函数。

构造函数的低保定理

如果你没写构造函数,类有一个默认的无参构造函数提供给你。(没钱时候国家发低保)
如果你写了构造函数,那么这个无参构造函数就消失了。(有钱的时候,低保没了)

成员变量的默认值

对象创建后,对象的成员变量都会被赋值默认值。

基本类型默认值
bye、short、int、long0
float、double0.0F(D)
booleanfalse)
char‘\u0000’

引用类型的默认值都为null

this的作用

  • 当局部变量与成员变量重名时,this指向成员变量(this代表当前的对象)。
public void setHour(int hour) {
        //小时的输入范围是[0,24)
        if (hour >= 24 || hour < 0) {
            System.out.println("error hour number!");
        } else {
            //例如下方代码
            this.hour = hour;
        }
    }
  • 调用构造函数(this调用语句必须写在构造函数方法的第一行)、普通函数(区分方法的定义来源)
public class Student {
    private String name;

    public Student() {
        //调用下方带参的构造函数(this必须写在第一行);
        this("游客");
        //调用普通的方法,区分方法的定义来源
        this.statusStudent();
    }

    public Student(String name) {
        this.name = name;
        System.out.println("正在赋值名字中....");
    }

    public void statusStudent() {
        System.out.println("该学生的名称为:" + this.name);
    }

    public static void main(String[] args) {
        Student student = new Student();
        /*
        运行结果:
            正在赋值名字中....
            该学生的名称为:游客
         */
    }
}

super的作用

  • 在子类中,调用父类覆盖的方法。
    多态中,如果子类重写了父类的某个方法,那么子类只能调用自己的重写方法,不能调用父亲的重写方法,super就是为了解决这个问题,可以通过super调用父亲的重写方法。
  • 子类的构造函数中,调用父类的构造函数。

修饰符与访问级别

在这里插入图片描述

POJO类的要求(plain ordinary java object)

  • 属性私有化
  • getter、setter
  • 书写默认构造函数
  • 重写equals和hashCode方法
  • 重写toString方法
  • 实现Serializable接口

static的作用

  • static修饰的变量叫静态变量(类变量)
  • static修饰的方法叫静态方法(类方法)
    因为static修饰的变量、方法属于类,不属于对象,所以静态变量又叫类变量、静态方法又叫类方法

静态变量

  • 所有对象共享静态变量的值
public class DemoOne {

    //姓名
    private String name;

    //可用电脑的数量
    private static int availableComputerNumber = 10;

    DemoOne(String name) {
        //属性赋值
        this.name = name;
        //当前可用电脑数量-1
        availableComputerNumber--;
        //输出日志
        System.out.println(name + "使用了一台电脑,当前可用电脑为" + availableComputerNumber + "台");
    }

    public static void main(String[] args) {
        //此时没有任何对象,我用类调用的变量,可直接说明,静态变量是属于类的。
        System.out.println(DemoOne.availableComputerNumber);

        //对象实例化
        DemoOne demoOne = new DemoOne("小明");
        DemoOne demoOne2 = new DemoOne("小红");
        DemoOne demoOne3 = new DemoOne("小蓝");
        /*
        运行结果为:
        10
        小明使用了一台电脑,当前可用电脑为9台
        小红使用了一台电脑,当前可用电脑为8台
        小蓝使用了一台电脑,当前可用电脑为7台

        发现了什么规律?
            static修饰后的变量,是公用的,大家都可以修改、使用这个值。
            name属性是属于对象,availableComputerNumber属性是属于类。因为所有的对象都可以使用、更改这个值。
         */
    }
}

静态方法

  • 静态方法内部只能使用静态变量和调用静态方法
    因为静态方法和静态变量在类加载的时候执行,那个时候,根本就没有对象,所以不能使用对象的成员变量、成员方法。
public class DemoTwo {
    private String name;

    private static void introduceAboutClass() {
        /*如果我使用name属性,会报错。调用method方法也会报错。
        
        因为name没有被static修饰,或者说静态函数内部只能使用静态变量和调用静态函数。
            为啥呢?静态是属于类,类加载时会执行静态变量和静态方法,那个时候还没有对象,哪来的成员变量?
         */

        System.out.println("我是xx类,我正在加载中");
    }

    public void method() {
    }

    public static void main(String[] args) {
        //用类调用静态方法
        DemoTwo.introduceAboutClass();
        /*
        运行结果:
        我是xx类,我正在加载中
        
        说明静态方法属于类
         */
    }
}

静态代码块

  • 类加载的时候默认执行
  • 静态变量可以看作特殊的静态代码块
public class DemoThree {
    static {
        System.out.println("我是静态代码块,类加载的时候,我就会执行。");
    }

    public static void main(String[] args) {

        /*
        输出结果:
            我是静态代码块,类加载的时候,我就会执行。
            
            顺便说一下,多个静态代码块,按照从上而下执行,而且静态变量可以看上特殊的静态代码块。
         */
    }
}

对象初始化的顺序

无继承

  1. 静态代码块(把静态变量当作静态代码块)
  2. 静态方法
  3. 成员代码块(把成员变量当作成员代码块)
  4. 成员方法
  5. 构造方法
public class DemoFive {
    private static String name;//第一步
    private String sex;//第三步

    //第二步
    static {
        System.out.println("静态代码块");
    }

    //第四步
    {
        System.out.println("代码块");
    }

    //第五步
    DemoFive() {
        System.out.println("构造函数");
    }

    public static void main(String[] args) {
        DemoFive demoFive = new DemoFive();
        /*
        运行结果:
            静态代码块
            代码块
            构造函数
         */
    }
}

有继承

  • 先静再动,先父再子。(静态的优先级大于父亲)
public class Son extends Father {
    //第三步
    private static String name;
    //第七步
    private String sex;

    //第四步
    static {
        System.out.println("儿子的静态代码块");
    }

    //第七步
    {
        System.out.println("儿子的代码块");
    }

    //第九步
    Son() {
        System.out.println("儿子的构造函数");
    }

    public static void main(String[] args) {
        Son son = new Son();
        /*
        运行结果:
            父亲的静态代码块
            儿子的静态代码块
            父亲的代码块
            父亲的构造函数
            儿子的代码块
            儿子的构造函数
            总而言之:先静态再动态,先父亲再儿子。静态的优先级大于父亲。
         */

    }
}

class Father {
    //第一步
    private static String name;
    //第五步
    private String sex;

    //第二步
    static {
        System.out.println("父亲的静态代码块");
    }


    //第六步
    {
        System.out.println("父亲的代码块");
    }

    //第八步
    Father() {
        System.out.println("父亲的构造函数");
    }
}

单例模式

学习资源

包装类

基本类型和包装类的关系

基本类型使用起来确实很方便,但是只有值,没有属性和方法。
如何让基本类型包含属性和方法呢?经过一番打怪升级,然后基本类型2.0就登场了,它的名字叫包装类。

包装类=基本类型+(属性、方法)+其他
在这里插入图片描述

/*
        基本类型直接赋值就可以使用了,根本不用对象实例化,使用起来好方便呀。
        *
        但是方便的同时必然有缺点,它只是个值,没有方法和属性
         */
        int a = 3;

        /*
        下方的代码和int a=3;起到了相同的效果
        但是int a =3;是基本类型,Integer b =new Integer(3);是包装类。
         */
        Integer b = new Integer(3);
        //包装类的方法,这是基本类型没有的东西
        System.out.println(b.compareTo(5));
        System.out.println(b.toString());
        
        /*
        包装类主要用于类型转换
            下面会介绍parsexxx和valueOf的区别
         */


        String c = "999";

        //把string类型转换成int类型  转换后返回的是基本类型
        int d = Integer.parseInt(c);

        //把string类型转换成int类型  转换后返回的是包装类
        Integer f = Integer.valueOf(c);

parseXXX和ValueOf方法的作用都是格式转换,但是parseXXX返回的是基本类型,valueOf返回的是包装类。

装箱

把基本类型转换为包装类。

拆箱

把包装类转换成基本类型。

final的作用

final本身的含义是“最终的,不可改变的”,它可以修饰非抽象类、非抽象方法和变量。

注意:构造方法不能使用final修饰,因为构造方法是最终的,肯定不能被继承。

final 修饰类

表示最终的类,该类不能再有子类(俗成公公类)

final 修饰方法

表示最终的方法,该方法不能被子类覆盖或重写

final 修饰变量

表示最终的变量,那么即为常量,该常量只能被赋值一次

继承

Java接口:我有很多个爸爸,而且他们只能是接口。
Java类:我不知道你们有几个爸爸,反正我只有一个爹。
Java接口:你在骂谁?是不是想打架?我有多个爸爸,你只有一个爸爸,打起来你必输无疑!
Java类:我虽然只有一个爹,但是我能实现多接口,我还有很多接口兄弟会帮助我!

父类

public class Animals {
    public Animals() {

    }

    protected String height;
    protected String weight;
    protected int averageAge;

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    public String getWeight() {
        return weight;
    }

    public void setWeight(String weight) {
        this.weight = weight;
    }

    public int getAverageAge() {
        return averageAge;
    }

    public void setAverageAge(int averageAge) {
        this.averageAge = averageAge;
    }

    protected void speak() {
        System.out.println("我是动物");
    }

    protected void beat() {
        System.out.println("动物打人");
    }

    protected void eat() {
        System.out.println("动物吃饭");
    }

}

子类

public class Dog extends Animals {
    /*
    虽然我类中只写一个构造函数,没有其他方法和变量
    但是我可以使用父类的方法和变量,如果我把这些方法在类中写出来了,那么就叫重写。
     */
    public Dog() {

    }



    public static void main(String[] args) {
        Dog dog=new Dog();
        dog.beat();
    }
}

继承的好处

  • 代码复用

将一些共有的属性和方法定义在这个类中,当某一个类需要使用到这些方法和属性的时候,直接继承该类,代码复用。

重写

小明有个父亲叫老明。
老明一辈子都在种地,他的座右铭是:要想不挨饿,就要脚踏实地种地。
然后老明把这个座右铭传给小明,但是小明看到大都市的赚钱门路,不想种地致富。所以小明把座右铭改为:大城市闯一闯,人生才宽广。

重写: 父类的方法,不满足子类的需求时可以进行覆盖Override它。

public class Father {
    protected void goldWord() {
        System.out.println("要想致富,就要种地");
    }
}
public class Son extends Father {

    /*
    我不同意父亲说的:要想致富,就要种地这句话
    我认为要想致富,就要去大城市闯一闯。所以我要重写父亲传给我的金句方法。
     */
    @Override
    protected void goldWord() {
        //不同意的父亲传给我的金句,所以对金句进行修改。
        System.out.println("要想致富,就要去大城市闯一闯");
    }
}

重写和重载的区别

  • 重写:两个方法必须有相同的返回值,函数名,参数列表,且子类中的方法的访问级别不能低于父类相应方法的访问级别。
    例如:父亲的某个方法访问级别为protected,那么子类重写该方法后的访问级别只能为protected、public
  • 重载:两个方法必须有相同的函数名,不同的参数列表(数量、类型、顺序),对返回值、访问级别没有要求。

多态

多态:父类的子类呈现多个形态。龙生九子,子子不同。

产生多态的必要条件:

  • 继承
  • 多态
  • 父类引用指向子对象
public class Father {
    protected void favoriteFood() {
        System.out.println("我是父亲,我喜欢吃馒头。");
    }

    public static void main(String[] args) {
        /*
        已经完成继承和重写
         */

        //完成父类引用指向子类对象
        Father person = new BigSon();


        person.favoriteFood();
        /*
        运行结果:
            我是大儿子,我喜欢吃米饭
         */
    }
}

class BigSon extends Father {
    @Override
    protected void favoriteFood() {
        System.out.println("我是大儿子,我喜欢吃米饭。");
    }
}

class SmallSon extends Father {

    @Override
    protected void favoriteFood() {
        System.out.println("我是小儿子,我爱吃煎饼。");
    }
}

父与子的转换

父转子

俗称向下转换

  • 需要判断实例是否属于对应的类
public class Father {
    protected void favoriteFood() {
        System.out.println("我是父亲,我喜欢吃馒头。");
    }

    public static void main(String[] args) {
        //父类引用指向子类对象
        Father father = new BigSon();

        /*
        强制转换虽然粗暴,但是存在一个隐患,如果father变量指向的实例不属于bigson类,那肯定会报错啊。
        所以需要判断一下实例是不是属于该类,这样更安全。
         */
        // 太过
        if (father instanceof BigSon) {
            //说明father变量指向的实例是属于BigSon类的,所以可以进行强制转换。
            BigSon bigSon = (BigSon) father;
        } else {
            System.out.println("父转子失败");
        }

    }
}

class BigSon extends Father {
    @Override
    protected void favoriteFood() {
        System.out.println("我是大儿子,我喜欢吃米饭。");
    }
}

class SmallSon extends Father {

    @Override
    protected void favoriteFood() {
        System.out.println("我是小儿子,我爱吃煎饼。");
    }
}

子转父

俗称向上转换

  • 转换后只能使用父类和子类共有的方法和属性
public class Father {
    protected void favoriteFood() {
        System.out.println("我是父亲,我喜欢吃馒头。");
    }

    public static void main(String[] args) {
        BigSon bigSon = new BigSon();

        /*
        向上转换,转换后的实例只能使用父类和子类共有的属性和方法
         */
        Father father = bigSon;
    }
}

class BigSon extends Father {
    @Override
    protected void favoriteFood() {
        System.out.println("我是大儿子,我喜欢吃米饭。");
    }

    public void play() {
        System.out.println("我是大儿子,我爱锻炼");
    }
}

class SmallSon extends Father {

    @Override
    protected void favoriteFood() {
        System.out.println("我是小儿子,我爱吃煎饼。");
    }
}

toString、equals、hashCode方法的重写

学习资源

抽象类

public abstract class Animals {
    /*
    1、大家都知道狗叫是汪汪,猫叫是喵喵。那么动物怎么叫?
    动物:我叫了个寂寞?
    *
    因为动物这个类太抽象,没有具体的表现形式,所以不知道怎么叫。
    既然不知道动物怎么叫,那么cry这个函数存在有什么意义呢?
    *
    cry函数的存在是为了动物的子类,猫狗鸡等,因为猫狗鸡有具体的叫声。
    *
    综上所得,动物的cry函数为了子类必须保留,但是动物的cry又没有什么意义。
    所以我们只需要留着动物cry函数的名字给后代使用,不需要cry函数的结构体。
    *
    2、不加结构体的方法必须是抽象方法,抽象方法必须是抽象类。所以在方法和类前面加上abstract。
    *
    3、抽象类为什么不能实例化?
    假设可以实例化,当实例化之后,对象要是打算cry,你cry个毛?你毛都没有,你怎么cry?
    *
    4、抽象类除了不能实例化剩下和普通类一样,常量、变量、构造函数都可以存在。
    *
    5、俗话说的好,老子未完成的事就交给儿子,儿子没完成就交给孙子.....
    动物有个后代叫食草动物,那你知道食草动物怎么叫吗?
    食草动物作为动物的子代不能实现cry这个函数,那怎么办?
    那么食草动物必须变成抽象类,然后把cry这个函数传给子代,让子代去实现这个函数
    年复一年,日复一日,直到有一个子类可以实现cry函数。
     */

    public abstract void cry();
}

抽象类的特征

  • 使用abstract关键字修饰类
  • 不能实例化对象
  • 不一定有抽象方法

抽象类的小知识

  1. 不能实例化
  2. 可以存在非抽象方法
  3. 可以没有抽象方法
  4. 可以存在构造函数
  5. 可以存在常量和变量
  6. 抽象类可以没有抽象方法,但是有抽象方法的一定是抽象类
  7. 如果子类不实现父类的抽象方法,那么子类必须要变为抽象类

接口

public interface FlyAble {
    /*
    1、jdk1.8以前,接口的定义:如果一个抽象类所有的函数都是抽象的,那么这个抽象类就叫接口。
    所以从某种形式上说,接口是抽象类的一种特殊情况。
    jdk1.8以后,接口中可以存在默认函数(default修饰)、静态函数(static修饰)。
    综上所得,jdk1.8以后:接口中只存在:
        公开静态常量(public、static、final)
        公开抽象函数(public、abstract)
        静态函数(static)
        默认函数(default)
    2、接口没有构造函数,所以不能实例化
    3、接口可以继承多个父类,父类必须为接口。
     */
    //常量
    public static final String INSTANCE = "100KM";

    //抽象函数
    public abstract void fly();

    //静态函数
    public static void someStaticMethod() {

    }

    //默认函数
    public default void someDefaultMethod() {

    }
}

接口的小知识:

  1. 接口可以有多个父亲,而且父亲必须是接口。
  2. 接口不能有构造方法、不能实例化。
  3. 接口内部不能出现变量
  4. 实现一个接口,必须重写接口中所有的方法

接口和抽象类的区别

学习资源

内部类

学习资源

异常

学习资源

时间、日期

学习资源

Math类

学习资源

正则表达式

符号作用
[]单个字符的的范围(例如[1-9])
{}左边字符的长度(例如[1-9]{3})
()普通的括号

详细知识

国际化

详细知识

集合

详细知识

大数的处理

详细知识

Collections

详细知识

多线程

详细知识

文件

详细内容

字节流和字符流

详细内容

对象序列化

详细知识

mysql

详细内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值