java基础

p460-470 List类子类的底层逻辑

JAVA基础

快捷键

ctrl+alt+L整理代码

shift+F10运行

ctrl+B定位找到方法

ctrl+H查看一个类的层级关系

ctrl+d复制当前代码项向下

shift+alt+上或下 将当前行代码上下移动

ctrl+f6重命名文件

ctrl+f 搜索

ctrl+j 显示所有快捷方式

Java要求

JAVA对大小写十分敏感,是强类型语言

一个源文件中最多只能有一个public类。其它类的个数不限

如果源文件包含一个public类,则文件名必须按该类名命名

一个源文件中最多只能有一个public类。其它类的个数不限,也可以将main方法写在非public类中,然后指定运行非public类,这样入口方法就是非public的main方法

注释(同C++)

单行注释==>//

多行注释==>/* */

文档注释 ==>/** */

参数信息:@author 作者名

@version 版本号

@since 指明需要最早使用的jdk版本

@param 参数名

@return 返回值情况

@throws 异常抛出情况

数据类型

数值类型

整数类型

整数

byte==>占1个字节范围:-128————127

short==>占2个字节范围:-32768-——————32767

int==>占4个字节范围:-214743648-——————2147483647

long==>占8个字节范围 Long类型要在数字后后面加个L

浮点类型 (小数)离散 舍入误差 大约 接近但不相等

float==>占4个字节范围 要在数字后后面加个F

double==>占8个字节范围

最好完全避免避免使用浮点数比较

银行业务表示钱不能用浮点数(浮点数误差),用BigDecimal 数学工具类

字符类型

单字符char==>占2个字节范围

String是字符串,但是String不是关键词,是类

boolean类型布尔值

占1为其值只有true和false两种

boolean flag = true;

引用类型

接口

数组

进制

二进制0b 0b1

八进制0 010

十六进制0x 0x10

类型转换

运算中,不同类型的数据先转化为同一类型,然后进行运算

强制转换 高==>低

自动转换 低==>高

转换的时候可能会内存溢出或者精度问题

 低———————————————------------—————————>高
 byte,short,char->int->long->float->double

String类型转为int使用Integer.parseInt( )

Object类型转String,在Object类型后面加一个"",双引号里不加任何东西

变量

局部变量(方法内部设变量)

实例变量(方法外部设变量)

从属于对象,如果不自行赋值则会输出默认值0 0.0 null

//布尔值的默认值是false

int age;
public static voif main(String[] args){
   Demo08 demo08 = new Demo08();
    System.out.println(demo08.age);
}//暂时不详细了解,平时用类变量代替

类变量(前面加上static,外部)

常量

final 常量名=值

final double PI=3.14;

可变参数

为避免方法重载过多,采用不定向参数

一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在他之前声明

public void  test(int... i){
}//由于不知道会有几个int数,所以直接采用可变参数

数组

int[] nums;//定义一个int类型的数组
nums = new int[10];//将这个数组设定为10个内容
int a[] = new int [5];//合并写法,等号前的括号可以在数组名的前或后都可以

获取数组长度方法 arrays.length

Arrays.sort(a); 把数组a排序(升序)

Arrays.toString(a);把a数组打印

Arrays.fill(a, val:0);用0将数组a填充

Arrays.fill(a,fromlndex:2, tolndex:4,. val:0);只填从2到4的位置,左开右闭

对于一个二维数组

map.length与map[ i ] . length不一样

前者是数列行的长度,后者是数列第i行的列的长度

赋值细节

数组的赋值是引用传递,赋的值是地址,赋值方式是引用赋值

把arr1赋值给arr2,相当于把arr1的地址赋值给arr2。如果arr2中的值发生改变,arr1的值也会改变

如果想进行数组拷贝,但是不是引用赋值

int [] arr2 = new int[arr1.length];//先根据arr1的长度创建一个数组,再用for循环挨个赋值

二维数组

二维数组的各个一维数组的长度可以不相等

二维数组的声明可以是[] [] y或y [] [] 或[] y []

二维数组开空间

int[][] arr = new int[3][];//先明确创建三个一维数组
arr[0] = new int[3];//给二维数组第一个一维数组开三个空间

冒泡排序

import java.util.Arrays;

public class 冒泡排序 {
    public static void main(String[] args) {
        int [] a={1,331,12,14,54,75,3};
        int[] sort=sort(a);
        System.out.println(Arrays.toString(sort));
    }
    public static int[] sort(int []array) {
        int temp = 0;
        for (int i = 0; i < array.length - 1; i++) {
            //外层循环,一共有多少个数字就循环多少次
            for (int j = 0; j < array.length - 1; j++) {
                //内层循环,每进行一次下一次循环少进行一步
                if (array[j + 1] > array[j]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            
        }
        return array;
    }
}

稀疏数组

如果一个数组里面的大部分元素为0或同一值;则可以采用此方法

处理方式:

1,记录数组一共有几行几列,有多少不同值。

2,把具有不同值的元素和行列及值记录在一个小规模的数组中

数组【0】用于记录行数列数与有多少不同值,余下数组记录值与他的位置

命名规范

1.只能由字母,数字,下划线,美元符号组成

2.不能以数字开头

3.区分同一个字母的大小写,即 hello 和 Hello 是不同的标识符

Java标识符一般有以下规范:

1.包名:全小写,如 java.awt.event, test

2.类名:首字母大写,如果由多个单词组成,要求每个单词的首字母都大写,如 HelloWorldApp

3.接口名:命名规则与类名相同。

4.方法名:往往由多个单词合成,第一个为动词,因此动词要全小写,后面的单词首字母大写,如

balanceAccount、isButtonPressed

5.变量名:一般为名词,全小写,如 area,lenth

6.常量名:全大写,如 MAX_INT, YEAR

7.对于变量名和方法,标识符不宜以“_” 和 “$” 为第一个字符,这两个字符对内部有特殊含义。

变量的命名规范

1.类成员变量:首字母小写和驼峰原则 monthSalary

2.局部变量:首字母小写和驼峰原则

3.常量:大写字母和下划线MAX_VALUE

4.类名:首字母大写和驼峰原则Man,GoodMan

5.方法名:首字母小写和驼峰原则 run(),runRun()

重载

一个方法可以写多种并且重名,每一种的参数体都不一样

缺省参数,定义函数时可以让最右边的连续若干个参数有缺省值

int func(int x1,int x2=2){ };
func(10)等效于func(10,2)
func(10,5)等效于func(10,5,2)
func(10, , 8)不可以,只能说最右边

new代码的理解(自己理解的)

Pet dog = new Pet();
  对象类型 对象名=new 对象值
  对象值实例化引出了他的一个对象dog,
  dog含有对象值的属性和方法
  堆中的dog会调用方法区中对象类型的方法
  所以方法最终一般是与左边有关
对象类型的变化其实就是多态,其本质就是子类继承了父类的方法,所以子类的对象可以调用父类的方法

方法设置

修饰符 返回值类型 方法名(参数)

没有返回值,则写入void;可以不写return或者只写return

静态

和类一起加载的

在其他类调用时只需要打 类名.方法名 即可

非静态

实例化new后才存在

在其他类里调用时,先将其实例化再用静态的调用方法

类实例化后会返回一个自己的对象

只能用public和默认来修饰

类的五大成员:属性,方法,构造器,代码块,内部类

默认初始化:

​ 数字:0 0.0

​ char:u0000

​ boolean:false

​ 引用:null

属性格式:修饰符 属性类型 属性名=属性内容

修饰符public>default(默认)>protected>private

对象的9大方法

  1. equals:判断两个对象的地址是否是同一个地址

  2. getClass:反射获取类信息(返回一个对象所属的类)(获取它的运行类型)

  3. toString:输出的是对象所属的类信息,以及对象地址

  4. hashCode

  5. notify

  6. notifyAll

  7. wait

  8. wait重载

  9. wait重载

    除了这九个方法,其他的都是人为写的

构造器 public 类名()

一个类即使什么都不写,他也会存在一个方法

使用new,必须要有构造器,隐藏存在的是一个无参构造器。如果类里面有含参构造器,则使用无参构造器时无参构造器不能隐形

alt+insert快速生成一个构造器

要求

​ 1.和类名相同

​ 2.没有返回值

作用

​ 1.new本质在调用构造方法(当同时包含有参构造和无参构造时,输入不同,调用的构造器不同)(程序走到new行代码后,会去类中找到复合的构造器并执行)

new Person();//调用无参构造
new Person(浩衡);//调用有参构造public Person(String name),浩衡就是输入构造器的name。此时在构造器中进行this.name = name;可以将浩衡赋给Person一个对象的属性name

​ 2.初始化对象的值(非常重要,在无参构造器中通过this将类的属性赋予初始值)

注意点:

​ 1.定义有参构造之后,如果想使用无参构造,显示的定义一个无参的构造

this.name代表这个类的一个属性name

访问修饰符

访问级别 访问控制修饰符 同类 同包 子类 不同包
公开 public
受保护 protected ×
默认 没有修饰符 × ×
私有 private × × ×

只有默认和public可以修饰类

封装 可以隐秘的进行合法检查

提高程序安全性,保护数据

隐藏代码的实现细节

统一接口

系统可维护性增加

判断合法输入,权限验证等代码都输入在封装里面。

高内聚,低耦合

属性私有(private int a;),get/set

私有的属性不能用s1.name这样去调用对象s1中的属性name

可以操作私有的方法:

​ get获得这个数据

​ set给这个数据设置值

在s1类里面

public String getName()
{
    return this.name;
}//设置获取数据的方法

public void setName(String name){
	this.name=name;
}//设置数据 

在主类里面

String name=s1.getName();
s1.setName("xx");

alt+insert可以快速设置get/set 选择getter and setter

越过检测

通过构造器,在实例化时就就把属性赋给对象,正常情况下可以跳过set里面的检测

解决方法:在构造器里调用set

&&&继承extends

在java中,所有类都直接或间接继承object类

a extends b;

public:子类继承父类的全部方法,属性(父类与子类有相同名字的属性时,子类.属性名调用的是子类的属性)

private无法继承

ctrl+H可以打开继承树

一般父类的属性采用private不进行继承,同时设置get/set,将这两个方法继承给子类。这样在实例化子类后,可以同时使用父类与子类的属性

java采用单继承,一个子类只能有一个父类。父类可以有多个子类。但是接口可以多继承

被final修饰的类不能有子类

super

this.xxx 调用该类里面的属性和方法

super.xxx 调用父类的属性与方法 私有无法被继承

调用父类的构造器必须在子类的第一行、

无参构造第一行有隐藏super,会调用父类的无参构造

父类没有无参,子类也不能有无参

super与this不能同时调用构造

this

调用本身

细节

子类必须调用父类的构造器,完成父类的初始化

当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类构造器中用super指定使用父类的哪个构造器完成父类的初始化

&&&重写override 需要是非静态方法

重写都是方法的重写

避免重写就用static

父类的引用指向子类

父类 b=new 子类();

最终用的时子类

重写的修饰符范围可以扩大protected>default>public

静态方法:方法的调用只和左边的数据类型有关

所有参数要一直,方法名称也要相同。但是返回类型可以不一样,子类返回类型可以是父类返回类型或者他的子类

子类不能缩小父类方法的访问权限

&&&多态

重要的几句话

  1. 一个对象的编译类型和运行类型可以不一致
  2. 编译类型在定义对象时就确定了,不能改变
  3. 运行类型是可以变化的
  4. 编译类型看定义时=号左边,运行类型看=号右边
Animal animal = new Dog()
//animal是对象引用,new Dog()是对象
//animal编译类型是Animal,运行类型是Dog

重写和重载就体现了多态

一个对象的实际类型是确定的,但是他的指向类型是不确定的

多态是方法的多态,属性没有多态

要有父子类型才能进行高转低 ClassCastException类型转化异常

存在条件:继承关系,方法需要重写,父类引用指向子类对象 Father f1=new Son();

无法重写:

​ static 方法,属于类,不属于实例

​ final 常量

​ private方法不能重写

向上转型

本质:父类的引用指向了子类的对象

语法:父类类型 引用名 = new 子类类型( );

特点:编译类型看左边,运行类型看右边

​ 可以调用父类中的所有成员

​ 不能调用子类的特有成员

​ 最终运行效果看子类的具体实现

编译(写代码)时看编译类型,运行结果看运行类型。所以调用属性,方法时只能找编译类型(父类的),运行结果看运行类型(先从运行类型的重写里面找,找不到就用父类的)

注意 属性的向上转型最后结果是看编译类型

动态绑定机制

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  2. 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());
        System.out.println(a.sum1());
    }
}

class A {//父类
    public int i = 10;
    //动态绑定机制:

    public int sum() {//父类sum()
        return getI() + 10;//20 + 10
    }

    public int sum1() {//父类sum1()
        return i + 10;//10 + 10
    }

    public int getI() {//父类getI
        return i;
    }
}

class B extends A {//子类
    public int i = 20;

//    public int sum() {
//        return i + 20;
//    }

    public int getI() {//子类getI()
        return i;
    }

//    public int sum1() {
//        return i + 10;
//    }
}

解释:

调用a.sum(),由于是向上转型,a的运行类型是B,所以从B类开始找,但是B类sum方法被注释掉了,不存在。于是去找父类A找到了,就使用A类的sum方法,由于动态绑定机制,所以sum中的getI方法还是从B开始找。

调用a.sun1(),同理,最后用A类的sum1,由于属性没有动态绑定机制,所以sum1中的i调用的是所处类(A)的属性i

向下转型

语法:子类类型 引用名 = (子类类型)父类引用;

只能强转父类的引用,不能强转父类的对象

要求父类的引用必须指向的是当前目标类型的对象

向下转型后可以调用子类类型中所有的成员

Animal animal = new Cat;//向上
Cat cat = (Cat) animal;//向下
//此处animal原本就是指向Cat的,所以可以向下转型。不能向下转型到Dog

instanceof和类型转换

instance可以判断是否有父子关系;

看instanceof前面的对象的运行类型是不是后面类型或者他的子类

Person person = new Student();
后面是比较的类型,而前面展开来说是person类型的student对象,所以与Teacher无关系
System.out.println(person instanceof Student); True
System.out.println(person instanceof Person); True
System.out.println(person instanceof Object); True
System.out.println(person instanceof Teacher); False
//System.out.println(person instanceof String); person与string没有一点关系,无法比较

//学长理解:instance左边是对象右边是要比较的类,对象属于右边类或者它的子类时是true 形式上:对象 instanceof 类

类型转换

低转高不需要强制转换,但是子类转换为父类可能会失去一些自己本来的方法,所以如果以后要低转高,最好在实例化时就用高

Student student = new Student;

Person person = student;

Person obj = new Student( );

目前无法调用子类obj(Student)的方法,需要将obj这个对象转换为Student类型

转换方法: Student student = (Student) obj;

此时在输入student.go( );就相当于调用了obj对象所在的Student类中的go方法

或者直接 ( ( Student ) obj ).go;

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

自定义一个类,就可以用这个类型建立数组,这个数组中可以放入他自己和他的子类的对象。各个对象的属性需要通过他们自己类里面的构造器放入数组中。

虽然没有放入方法的代码,但是可以直接调用对象的父类重写方法,并且符合动态绑定机制。比如Person[i]编译类型是Person,但是运行类型是要看传入数组时右边实例化的类的类型

调用子类特有方法:无法像父类重写代码一样直接调用。先用instanceof判断person[i]的运行类型是不是Student类型或者他的子类,如果是的话,就用向下转型为Student,于是就可以调用Student的特有方法

多态参数

方法定义的形参类型为父类类型,实参类型允许为子类类型

例子:

Worker和Manager都继承于Employee。 他们都重写了父类的getAnnual方法

在主程序里可以定义一个方法,参数为形参Employee e,方法里面调用getAnnual的话,由于动态绑定机制,他们可以调取各自的getAnnual方法

Object类

==

既可以判断基本类型,又可以判断引用类型

基本类型判断值,引用类型判断地址,即看是不是同一个对象(是不是指向同一个对象空间(等号左边指向右边)

Interger integer1 = new Integer(1000);
Interger integer2 = new Integer(1000);
//integer1 == integer2为假,因为1和2的Integer是new出来的,实际地址(对象空间)是不一样的

'A'==65 为真

equals

Objct类中的方法,只能判断引用类型

默认判断对象地址是否相等,子类种往往重写该方法,用于判断内容是否相等

重写equals

class Person{ //extends Object
    private String name;
    private int age;
    private char gender;

    //重写Object 的 equals方法
    public boolean equals(Object obj) {
        //判断如果比较的两个对象是同一个对象,则直接返回true
        if(this == obj) {
            return true;
        }
        //类型判断
        if(obj instanceof  Person) {//是Person,我们才比较
            //进行 向下转型, 因为我需要得到obj的 各个属性
            Person p = (Person)obj;
            return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;//name.equals调用的是String里重写的equals,比较是不是同一类型的同时比较内容是否一样
        }
        //如果不是Person ,则直接返回false
        return false;
    }
    
 //该equals可以判断两个对象是不是都是Person类的同时,判断三种属性是不是都一样。可以用来查重

hashCode(学完集合再深入)

5个小结论

  1. 提高具有哈希结构的容器的效率!
  2. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
  3. 两个引用,如果指向的是不同对象,则哈希值是不一样的
  4. 哈希值主要根据地址号来的!,不能完全将哈希值等价于地址。
  5. 后面在集合中hashCode如果需要的话,
    也会重写

toString方法

默认返回:全类名(包名+类名)+@+哈希值的十六进制

子类往往重写toString用于返回属性

子类的重写可以用alt+insert快速调用

System.out.println(monster);
//等价于
System.out.println(monster.toString());
//当直接输出一个对象时,toString方法会被默认的调用

finalize方法

当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作

回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。

Car bmw = new Car("宝马");
bmw = null;//bmw变为空,就与Car断了联系,此时car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象空间,在销毁前,会调用这个对象的finalize方法
//这时可以在finalize方法里面写一些自己想要执行的代码

同样可以直接用alt+insert重写

垃圾回收机制的调用是由系统决定的,但是也可以通过System.gc( )主动触发垃圾回收机制(但也不是百分之百,不会阻塞代码,相当于提醒系统回收)

实际开发中,几乎不会运用到finalize,更多是为了应付面试

main方法

  • mian方法由java虚拟机调用,所以权限要设置为public
  • 虚拟机在执行mian时不需要建立对象,所以用static
  • args数组
  • main是一个静态方法,这就是为什么对于非静态类要先实例化才能调用方法
  • idea中可以动态传参

代码块

[修饰符]{

​ 代码

}; 分号可以写也可以省略

和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用

注意

  • 修饰符只能是static(静态代码块)或者没有(普通代码块)

相当于另外一种形式的构造器(对构造器的补充机制)

如果多个构造器有重复的语句,可以抽取到初始化块中,提高代码复用性

不管调用哪个构造器,创建对象都会先调用代码块里的内容

代码块调用的优先级高于构造器

细节:

  1. 静态代码块随着类的加载而执行,并且执行一次。普通代码块每创建一个对象就执行一次(加载不等于创建)

    • 类什么时候被加载:
      • 创建对象实例时(new)
      • 创建子类对象实例时,父类也会被加载
      • 使用类的静态成员时(静态方法,静态属性)
  2. 如果使用类的静态成员时,普通代码块并不会执行

  3. 调用顺序:

    • 先调用静态代码块和静态属性初始化(他们优先级一样,如果都有,则按他们定义的顺序调用)

    • 再调用普通代码块和普通属性的初始化(他们优先级也一样)

    • 最后调用构造方法(构造器)

  4. 构造器最前面其实隐含了super()和调用普通代码块

    所以顺序是先调用父类的构造器(同样进行这样的隐藏规则),然后调用自身的普通代码块,最后进行构造器中的内容

  5. 静态代码块只能直接调用静态成员,普通代码块都可以

static关键字详解

使用static去new类,可以保证资源只有一份

静态变量(类变量)

private static int age;//静态变量
    private double score;//非静态变量

        A a = new A();
       
System.out.println(a.score);
System.out.println(a.age);
        System.out.println(A.age);//类变量

静态变量可以使用类变量的形式,所以一般静态变量都采用类变量形式,方便确实他是静态变量

静态变量在多线程中会用到

在类中用public static 修饰变量,就可以使这个类的所有对象共享

类变量可以通过对象或者类名(推荐)进行访问

类变量随着类的加载而创建的,所以即使没有创建对象实例也可以访问

定义语法:

访问修饰符 static 数据类型 变量名;(推荐)

static 访问修饰符 数据类型 变量名;

静态方法(类方法)

非静态要先new后调用,非静态方法可以调用静态方法

静态方法在本类中可以直接go( );调用,或者 类名 . go( );

静态方法只能调用静态方法或静态变量(静态方法与类一起先加载出来,而此时非静态变量还没有加载出来,所以不能调用)

普通成员方法都可以访问(静态与非静态)

创建方法与静态变量相同

使用场景:当方法中不涉及到任何和对象相关的成员.则可以将方法设计成静态方法提高开发效率。这样可以不实例化对象就调用方法

类方法中无法使用和对象有关的关键词,比如this和super

静态代码块(狂神)

代码块:在程序中直接加入{ },并在其中写代码叫做匿名代码块。心得对象一创建,会先走匿名代码块(有多少个对象就一共会执行多少次),再走构造器

静态代码块:static{ }类加载时就执行,且永久只执行一次(根据这些特性,常用来赋初始值)

静态导入包

正常使用生成随机数函数,每次都要写Math . random( )

为了减少输入量,可以像C++库(#include math.h)一样将Math所在的包导入到代码开头

import java.lang.Math;

如果想详细的把包里的某个方法调用就需要用到静态导入包

import static java.lang.Math.random;//多加了一个static

final

可以修饰类,属性,方法和局部变量

用法

  1. 不希望类被继承(修饰类)
  2. 不希望父类的某个方法被子类覆盖/重写(修饰方法)
  3. 不希望类的某个属性的值被修改(修饰属性)
  4. 不希望某个局部变量被修改(修饰局部变量)

细节:

  1. final修饰的量又叫常量,一般用XX_XX命名
  2. final修饰的属性在定义时,必须赋初值并且以后不能再修改。赋值可以在如下位置
    • 定义时
    • 构造器中
    • 代码块中
  3. 如果final修饰的时静态属性,则不能在构造器中赋值
  4. final不能继承,但hi可以实例化对象
  5. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承
  6. 一个类已经是final类了,就没有必要再用final修饰方法了(这个类已经不能继承了)
  7. final不能修饰构造方法
  8. fianl常常和static搭配使用,效率更高(仅用static修饰属性,虽然类不会被创建但是也会被加载,final static修饰的则不会被加载)(两个修饰词的顺序可以颠倒)
  9. 包装类(Integer,Double,Float,Boolen)等都是fianl,String也是final
  10. 形参可以用final

抽象类

用abstract修饰可以形成抽象类,抽象方法;就是只有名字没有内容

抽象类的所有方法,继承了他的子类,都必须要去实现他的方法。除非这个子类也是抽象类

抽象类不能实例化,只能靠子类去实现它

抽象类里可以写普通方法,抽象方法必须在抽象类里

注意:abstract与final不能一起用,抽象需要继承,而final不允许继承。也不能与static连用,因为static不能被重写

抽象的目的就是设计架构,比如LOL中英雄各不相同,但是他们的属性类型(ad,ap)和技能组都是共同的。写好架构以后每一个英雄只需要跟着架构进行继承与重写,就能在固定的游戏玩法架构下成就多样性

接口的定义与实现 interface

接口不能写方法,抽象类里还可以写普通方法(jdk8.0后接口可以有静态方法,默认方法(default))

使用细节

  1. 接口也不能被实例化
  2. 接口中的所有定义都是抽象的,方法默认public abstract,属性默认是常量public static final(所以必须初始化)(可以不实例化直接访问)
  3. 一个普通类实现接口,要实现接口的所有方法
  4. 抽象类实现接口,可以不用实现接口的方法,快捷键Ctrl+i或者alt+enter
  5. 一个类可以是继承多个接口
  6. 接口不能继承其他类,但是可以继承多个别的接口

接口的多态

  1. 接口类型的变量可以指向实现了IF接口的对象实例,类似于父类指向子类

  2. 可以放入接口数组中,也就是多态数组

  3. 接口存在多态传递现象:a实现了b接口,b接口继承了c接口,则a实例化时可以向上转型为b或c(相当于teacher也实现了c接口)

接口都需要有实现类,通常用i(i大写)mpl结尾 实现类的关键字是implements

声明接口的关键词时interface

用法

要管理多个数据库,经理定义一个接口,可以规范程序员方法,变量的名字,同时可以方便调用

调用:多种数据库代码重写接口,定义一个方法,参数是接口类的类型,方法中调用抽象类的方法。则如果将某重写类传入这个方法中,就可以调用这个类重写的方法。

N种内部类

在一个类中再定义一个类,就是内部类

一个java类中可以有多个class但是只能有一个public class

最大特点是可以直接访问内部属性,并且可以体现类与类之间的包含关系

分为两类

  • 定义在外部类局部位置上(比如方法内)
    • 局部内部类
    • 匿名内部类
  • 定义在外部类的成员位置上
    • 成员内部类
    • 静态内部类

局部内部类(有类名)

通常是在方法里,也可以是代码块等

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为他的地位就只一个局部变量(存在于方法内部的变量),但是可以使用final修饰(局部变量也可以)
  3. 作用域:仅仅在定义它的方法或代码块中
  4. 访问内部类的方法:外部类可以实例化内部类然后调用内部类的方法(必须在作用域内)
  5. 外部其他类不能访问局部内部类
  6. 如果外部类和局部内部类的成员重名,默认遵循就近原则,如果想在局部内部类中访问访问外部类的成员可以使用this。外部类名. this可以理解为外部类的对象,谁调用了含有this的方法,这个对象就是谁

匿名内部类(没有类名)

1)本质是类 2)是内部类 3)还是一个对象

细节

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为他的地位就只一个局部变量
  3. 作用域:仅仅在定义它的方法或代码块中
  4. 匿名内部类访问外部类成员可以直接访问
  5. 外部其他类不能访问匿名内部类(因为是局部变量)
  6. 重名,就近原则

应用场景:想使用IA接口并创建对象。传统方法血药写一个新类重写接口,然后实例化这个接口。但是如果只是用一次的话传统方法太过麻烦,可以使用匿名内部类来简化

IA tiger = new IA(){
  //实现IA类  
};
//IA写在Outer类的method方法中

tiger的编译类型是IA,运行类型是匿名内部类。

实际上底层会先创建一个Outer$1(系统分配)的类实现接口(隐藏),表面上是把这个类实例化为tiger。

匿名内部类只能使用一次(Outer$1这个类在实例化后就不存在了,不能实例化出第二个对象),而匿名内部类生成的对象可以无限次调用

匿名内部类可以用于接口,也可以用于抽象类

进一步理解

Father father = new Father("jack"){};

如果没有大括号,那么father的运行类型就是Father。加上大括号,运行类型就是一个匿名内部类(类名是系统分配的),这个类里的代码就是大括号里的代码

因为本质是创建一个对象,所以最后加分号

调用方式

由于匿名内部类即使类又是方法,所以有两种调用方法

作为类:用对象接收(实例化),然后调用这个对象的方法

作为对象:直接

new Person(){
    //重写代码hi
}.hi();
//hi()前面的一堆实际上是个对象

实际用法

匿名内部类可以当作实参直接传递

这样的话,如果方法的形参是接口类型的话,就可以不用新建一个类去实现接口,直接在匿名内部类中实现

成员内部类(没用static)

定义在外部类的成员位置

  1. 可以直接二访问外部类的所有成员,包括私有的
  2. 由于他的地位是一个成员,所以可以用四种修饰符修饰
  3. 作用域和外部类的其他成员一样
  4. 成员内部类访问外部类可以直接访问
  5. 外部类访问内部类要先创建对象后访问
  6. 其他外部类访问成员内部类有三种方法(第三种是第二种的改版,把两个实例化语句合并)
//方法一
Outer outer = new Outer();//先实例化外部类
Outer.Inner inner = outer.new Inner();//在实例化成员内部类

//方法二:在外部类中编写一个方法,可以返回成员内部类对象
public Inner getInnerInstance(){
    return new Inner();
}

Outer outer = new Outer();
Outer.Inner innerInstance = outer.getInnerInstance();//此处是方法返回对象,相当于已经实例化过了,所以不用new
  1. 外部类与内部类成员重名,就近原则,访问外部类用this

内部类可以获得外部类的私有属性和私有方法

静态内部类(使用static)

public static class//生成内部类
  1. 由于比外部类先生成所以无法获得外部类的东西,但可以直接访问外部类的所有静态方法,包括私有的
  2. 可以添加四种修饰符
  3. 作用域同其他成员,为整个类体
  4. 静态内部类访问外部类可以直接访问
  5. 外部类访问静态内部类需要创建对象再访问
  6. 外部其他类访问静态内部类
//方式一,静态内部类是可以直接通过类名访问的
Outer outer = new Outer();
Outer.Inner inner = new Outer. Inner();
//方式二,写一个方法返回静态内部类对象,与成员内部类一样
  1. 就近原则,访问外部类成员用外部类名.成员。此处不能用this,因为这个访问的成员是静态的(细节1)

枚举类enum

枚举是一组常量的集合,属于一种特殊的类,里面只包含一组有限的特定对象

enum不能继承其他类,因为他已经继承了Enum类

枚举类跟其它类一样,也可以实现接口

枚举的实现方式:

  1. 自定义类实现枚举
  2. 使用enum关键词实现枚举

使用enum关键词实现枚举注意事项:

  1. 使用enum关键字开发一个枚举类时,默认继承Enum类,而且是一个final类
  2. 必须要说明用哪个构造器
  3. 如果使用无参构造器,创建常量对象时可以省略(),相当于直接写常数名
  4. 枚举对象必须放在枚举类的行首
  5. 可以把枚举常量赋给其他对象
Gender boy = Gender.BOY;
Gender boy2 = Gender.BOY;
//Gender枚举类中有BOY常量,该语句是在其他类中的
sout(boy);//本质就是调用Gender类的父类:Enum类的toString,他的方法内容是返回name(枚举常量名)
sout(boy2==boy)//相等(枚举常量是静态性质的,只有一个)

自定义枚举实现

  1. 将构造器私有化,防止被实例化,成为只读
  2. 去掉set的方法,只能读不能修改,提供get方法
  3. 在类内部直接创建固定的对象
  4. 枚举对象通常全部大写
  5. 可以重写toString
class Season{
	public static final Season SPRING = new Season(使用私有构造器进行初始化);
}
//public使外部可以访问,static使外部可以直接访问,final防止类提前加载(属于优化)
//类的外部其他类就可以直接Season.SPRING直接访问

使用enum关键词实现枚举

  1. 使用关键词enum替代class
  2. 构造器,get方法,toString等都可以保留,要改变对象创建的方法
public static final Season SPRING = new Season(使用私有构造器进行初始化);
//代替为
SPRING(使用私有构造器进行初始化);//常量名(实参列表)
  1. 如果有多个常量(对象),使用,间隔
SPRING(使用私有构造器进行初始化),
SUMMER(使用私有构造器进行初始化),
AUTOMUN(使用私有构造器进行初始化);
  1. 要将定义的常量对象写在最前面,对象属性也要写在定义后面

Enum成员方法

由于枚举类继承了Enum,所以可以使用它的成员方法

  1. name建议使用toString
  2. ordinal输出的是该枚举对象的编号(从0开始编号,可以知道是第几个创建的常量)
  3. values,通过枚举类使用(不是常量),可以返回一个数组,含有定义的所有枚举对象(不是对象名,而是对象本身,数组类型与枚举类类型相同)
  4. valueOF将字符串转换为枚举对象,要求字符串必须为已有的常量名,否则会报错
  5. compareTo,比较两个枚举常量,比较的就是位置号 返回值为两者位置号的差值

注解Annotation

注解也被称为元数据,用于修饰包,类,方法,属性,构造器,局部变量等数据信息

注解不应行啊程序逻辑但是可以被编译或运行,相当于嵌入在代码中的补充信息

JAVAEE中使用的较多

写与不写其实结果一样,只是为了说明

jdk5.0加入了接口注解

@Target是修饰注解的注解,成为元注解

三种注解

@Override重写

限定某个方法是重写父类,该注解只能用于方法

如果写了,编译器会检查是否真的重写了父类的方法,如果是假的则会报错(相当于是语法校验)

@Deprecated过时

表示某个程序元素(类,方法等)已过时

可以修饰方法,类,字段,包,参数等等

可以做到新旧版本的兼容和过渡

过时不代表不能用,是不推荐使用

@SuppressWarnings抑制警告

可以让编译器给出的黄色警告不显示

@SuppressWarnings({" "}),双引号中写入相一致的警告类型(要查)

作用范围和放置的位置有关

异常

防止因为一个不算致命的异常导致整个系统崩溃

如果进行了异常处理,那么即使出现了异常,程序也可以继续指向

e.getMessage( )可以返回异常信息

ERROR一般是程序无法控制的,是灾难性的错误。Exception是可以被程序处理的,分为两种:运行时异常(编译器没有提示,要自己判断)和编译时异常

运行异常默认是抛出

异常处理

五个关键字:try catch finally throw throws

try{//try监控区域
    代码;
}catch(异常类型 命名){//捕获异常,可以并列着写多个异常,但是要按从小到大排序
    打出一些句子来提醒自己;
}finally{//不管程序出不出现异常,都会执行,程序崩掉前也会执行
    代码;
}
//这样程序就不会报错。   try catch必须有,finally可选(通过关闭代码可以保证程序会关闭)

Ctrl+Alt+T可以快速生成catch

e(这是个名字).printStackTrace();//可以打印错误的栈信息

可以用来判断输入的是否为整数(Integer.parseInt能把字符串变为int,但是有异常)

抛出异常

throw new 异常类型();//主动抛出异常

一般写在方法里,假设这个程序处理不了,可以在方法上抛出异常

throws写在方法后public void test(int a) throws 异常类型;再用try catch接收

把异常抛给父类,父类可以选择继续向上抛或者trycatch。最高级为JVM。JVM处理异常方法:1.输出异常信息 2.退出程序

不做处理默认是抛出,实际上不做处理运行后中断就是因为JVM输出后退出了程序

自定义异常

继承Expection类,这个类就是自定义编译异常类

继承RuntimeException,属于运行异常

可以用来判断合法输入

一般自定义运行异常,因为编译异常还要throws

throws写在方法声明处,后面跟异常类型。throw写在方法体中,后面跟异常对象

常用类

包装类

包装类和基本数据的转换

以int与Integer为例

装箱:基本数据类型到包装类。 拆箱:包装类到基本数据类型

jdk5之前是手动装箱拆箱

//手动装箱
int n1 = 100;
Integer integer = new Integer(n1);\
//或者
Integer integer1 = Integer.valueOf(n1);

//手动拆箱
int i = integer.intValue();

jdk5后可以自动装箱拆箱

int n2 = 200;
//自动装箱
Integer integer2 = n2;
//自动拆箱
int n3 = integer2;

包装类型与String类型相互转换

Integer i = 100;//自动装箱
//包装类转String 
//方式1
String str1 = i + "";
//方式2
String str2 = i.toString();
//方式3
String str3 = String.valueOf(i);

//String转包装类
String str4 = "12345";
//方式1
Integer i2 = Integer.parseInt(str4);
//方式2
Integer i3 = new Integer(str4);

只要有基本数据类型,那么==判断的就是数值

String

字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节

String s = 字符串//直接赋值
String s1 = new String();//空的字符串对象
String s2 = new String(字符串);//初始化有内容的
String s3 = new String(char[] a);//数组转字符串对象
String s4 = new String(char[] a,int startIndex,int count);//输入开始位置与选取多少个数组元素
//还有许多其他的构造器

String实现了Serializable,说明String可以串行化(可以在网络里传输),实现了Comparable,说明可以比较。String是final类,不可以被继承。

String有一个属性是数组,用来存放字符串内容,这个数组是final类型的,赋值后不可以修改(指的是地址,不能指向新的地址,但是可以修改他的内容(在原来的地址处修改内容)。)

String s = "ABCabc";
System.out.println("s = " + s);
s = "123456";//正常
System.out.println("s = " + s);
string s2 = "123";
s = s2;//报错

注意,s只是这个对象的一个引用,s=123456执行后,又创建了一个新的对象,而s引用指向了这个新的对象,原来的对象仍然存在。所以多次使用这种修改方式会生成很多垃圾

方法

  • equals区分大小写,判断内容是否相等
  • equalsIgnoreCase忽略大小写的判断内容是否相等
  • length获得字符的个数,字符串的长度
  • indexOf获取字符在字符串中第一次出现的索引,索引从0开始,找不到返回-1(也可以查字符串)
  • lastIndexOf获取字符在字符串中最后一次出现的索引,索引从0开始,找不到返回-1
  • substring截取指定范围的字串
  • trim去前后空格
  • charAt获取某索引处的字符,注意不能使用Str[index]这种方法
  • toUpperCase全转为大写
  • toLowerCase全转为小写
  • concat拼接字符
  • replace替换字符串中的字符,把所有的xx替换为xx。返回的结果才是替换过的
  • split分割字符串,返回值放入一个字符串数组中。对于 |,\\等需要用转义字符,想要以\\进行分割,就要输入\\\\,13为转义
  • compareTo比较字符串大小,相同返回0,否则返回正数负数。(原理:先得到两个字符串最小长度,看最小长度内的字符串是否相同,相同的话返回值为两个字符串长度差值,如果不相同,返回的是第一次出现差异位置的字母插值)
  • toCharArray转换为字符数组
  • format将一系列类型的数据组合在一起,组合的方式与C++中printf一致

StringBuffer类

很多方法与String相同,但是长度可以变

StringBuffer是一个容器

String的value数组在堆中,内容在常量池中,每次修改都会在常量池中新建,并且更改指向

StringBuffer的value数组在堆中,内容也在堆中,并且这个数组可以扩容与修改内容。不用每次都创建新对象,效率高

构造器

StringBuffer stringBuffer = new StringBuffer();//创建一个大小为16的char数组
StringBuffer stringBuffer = new StringBuffer(int capacity);//创建一个大小为capacity的char数组 
StringBuffer(String string);//创建一个大小为string长度+16的char数组

方法

  • append追加
  • delete(start,end)删除,左闭右开
  • repalce(start,end,string)替换
  • indexOf查找第一次出现的位置,找不到返回-1
  • insert插入
  • length

String与StringBuffer转换

String转StringBuffer

  1. 使用要求输入字符串的构造器
  2. 先使用无参构造器创建对象,然后使用append方法追加

StringBuffer转String

  1. 使用toString方法
  2. 使用String构造器,直接传入

StringBuilder

不是线程安全的

作为StringBuffer的一个简易替换

单线程优先使用该类,效率最高

Math

都是静态方法

  • abs绝对值
  • pow求幂
  • ceil向上取整,返回该参数的最小整数(转成double)
  • floor向下取整,返回该参数的最大整数(转成double)
  • round四舍五入(转成long)
  • random求随机数,返回的是0到1的随机数(可以为0)
  • max求两个数最大值
  • min求两个数最小值

Arrays类

方法

  • toString返回一个字符串,能把数组内容拼接为一个字符串
  • sort有自然排序与定制排序,会直接影响到实参。sort可以重载。定制排序实现了Comparator接口的匿名内部类,要求实现compare方法,方法返回值的正负会影响排序方式
  • binarySearch通过二分搜索查找,要求必须排好序,如果不存在就返回-(low+1),low是小于输入数的第一个数的位置
  • copyOf从arr数组中拷贝,有返回值。输入的长度如果大于arr长度,用null补全。
  • fill填充数组
  • equals比较两个数组元素内容是否完全相同
  • asList将一组值转换成list集合

BigInterger/BigDecimal

前者适合保存比较大的整数,后者适合保存精度较高的浮点数

方法

不能正常使用加减乘除符号,要使用方法

  • add加
  • subtract减
  • multiply乘
  • divide除,BigDecimal 可能会出现异常(结果为无限循环小数)。解决方法:divide方法中输入第二个参数作为精度,输入BigDecimal.ROUND_CEILING,如果有无限循环小数,就会保留分子的精度

System类

方法

  • exit退出当前程序,一般主动退出都是填0
  • arraycopy赋值数组元素,比较适合底层调用。一般用Arrays类的copyOf
  • currnetTimeMillens返回当前时间距离1970/1/1午夜的差异,以毫秒为单位
  • gc运行垃圾回收机制

日期类

第一代 Date

//1. 获取当前系统时间
//2. 这里的Date 类是在java.util包
//3. 默认输出的日期格式是国外的方式, 因此通常需要对格式进行转换
Date d1 = new Date(); //获取当前系统时间
System.out.println("当前日期=" + d1);
Date d2 = new Date(9234567); //通过指定毫秒数得到时间
System.out.println("d2=" + d2); //获取某个时间对应的毫秒数
//


//1. 创建 SimpleDateFormat对象,可以指定相应的格式
//2. 这里的格式使用的字母是规定好,不能乱写.网上查

SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1); // format:将日期转换成指定格式的字符串
System.out.println("当前日期=" + format);


//1. 可以把一个格式化的String 转成对应的 Date
//2. 得到Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换
//3. 在把String -> Date , 使用的 sdf 格式需要和你给的String的格式一样,否则会抛出转换异常
String s = "1996年01月01日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println("parse=" + sdf.format(parse));

第二代 Calendar

//1. Calendar是一个抽象类, 并且构造器是private
//2. 可以通过 getInstance() 来获取实例
//3. 提供大量的方法和字段提供给程序员
//4. Calendar没有提供对应的格式化的类,因此需要程序员自己组合来输出(灵活)
//5. 如果我们需要按照 24小时进制来获取时间, Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY
Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
System.out.println("c=" + c);
//2.获取日历对象的某个日历字段
System.out.println("年:" + c.get(Calendar.YEAR));
// 这里为什么要 + 1, 因为Calendar 返回月时候,是按照 0 开始编号
System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("小时:" + c.get(Calendar.HOUR));
System.out.println("分钟:" + c.get(Calendar.MINUTE));
System.out.println("秒:" + c.get(Calendar.SECOND));
//Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
    
System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH) +" " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) );

问题:

  1. 可变性:像日期和时间这样的类应该是不可变的
  2. 偏移性:Date中的年份是从1900开始的,而且月份都是从0开始的
  3. 格式化:格式化只对Date有用,Calendar不行
  4. 他们不是线程安全的,不能处理闰秒等(每隔两天,多出1s)

第三代

LocalDate日期,年月日

LocalTime时间,时分秒

LocalDateTime日期时间,年月日(最常用)

Instant时间戳

LocalDateTime方法

  • now返回当前日期时间的对象
  • getYear/getMonth/getMonthValue(得到数字)/getDayOfMonth......
  • DateTimeFormatter的对象可以进行格式化
  • format,采用格式对象进行格式化,返回修改后的字符串
  • toInstant可以把date转为Instant
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.now();
//提供 plus 和 minus方法可以对当前时间进行加或者减
//看看890天后,是什么时候 把 年月日-时分秒
LocalDateTime localDateTime = ldt.plusDays(890);

//看看在 3456分钟前是什么时候,把 年月日-时分秒输出
LocalDateTime localDateTime2 = ldt.minusMinutes(3456);

Instant方法

  • now
  • from,可以把instant对象转成Date

集合

数组缺点:

1)长度开始时必须指定,而且一旦指定,不能更改
2)保存的必须为同一类型的元素
3)使用数组进行增加/删除元素的示意代码-比较麻烦

集合优点:

1)可以动态保存任意多个对象,使用比较方便!
2)提供了一系列方便的操作对象的方法:add、
get,set、remove等
3)使用集合添加,删除新元素的示意代码-简洁了

集合主要分为两组:单列集合,双列集合

Collenction接口有两个重要的子接口List Set,他们的实现子类都是单列集合

Map接口的实现子类是双列集合,存放的K-V

image-20221110103447007

Collection接口实现类特点

  1. 可以存放多个元素,每个元素可以是Object类
  2. 有些可以存放重复的元素,有些不可以
  3. 有些是有序的(List),有些是无序的(Set)
  4. Collection接口没有直接的实现子类,是通过他的子接口List,Set实现的

Collection接口常用方法

以实现子类ArrayList来演示

1)add:添加单个元素

2)remove:删除指定元素

3)contains:查找元素是否存在

4)size:获取元素个数

5)isEmpty:判断是否为空

6)clear:清空

7)addAIl:添加多个元素

8)containsAll:查找多个元素是否都存在

9)removeAll:删除多个元素

10)说明:以ArrayList实现类来演示

Collection接口遍历元素方法

1.使用迭代器Iterator

所有实现了Collection接口的集合类都有一个iteratorO方法,用以返回一个实现了Iterator接口的对象,即可以返回一个选代器

Iterator仅用于遍历集合,本身并不存放对象

原理:while中使用hasNext方法判断是否还有下一个元素,循环中通过next方法可以让指针下移并将下移以后集合位置上的元素放回。如果比用hasNext判断,当next下移到无效记录时会抛出异常

快速生成迭代器while,输入itit,回车

如果想再次使用,给本来的迭代器对象再赋值一次iterator方法

2.增强for

可以理解为简化版的迭代器

语法:

for(元素类型 元素名 : 集合名或数组名){

​ 访问元素

}

快速生成:输入大写I,回车

List接口

  1. List集合类中元素有序(即添加顺序和取出顺序一致)且可重复
  2. List集合中的每个元素都有其对应的顺序索引,即支持索引。
  3. List实现子类中常用的是ArrayList,LinkedList,Vector

方法

  1. add
  2. addAll
  3. get 获取指定index位置的元素
  4. indexOf
  5. LastIndexOf
  6. remove
  7. set指定index位置的元素为ele(两个参数)

ArrayList

  1. all permits including null,Arraylist可以加入null,并且 多个
  2. ArrayList是由数组来实现数据存储的
  3. ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码,在多线程情况下,不建议使用ArrayList

LinkedList

  1. LinkedList实现了双向链表和双端队列特点
  2. 可以添加任意元素(元素可以重复),包括null
  3. 线程不安全,没有实现同步

如何选择ArrayList和LinkedList

1)如果我们改查的操作多,选择ArrayList
2)如果我们增删的操作多,选择LinkedList
3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList.

Set接口

  1. 无序(添加的顺序与取出的顺序不一样),没有索引
  2. 不允许重复元素,所以最多包含一个null
  3. 常用的有HashSet,TreeSet

常用方法与collection一样

遍历方式可以使用迭代器或增强for,但是不能使用普通for(不能使用索引的方式来获取)

HashSet

  1. 实现了Set接口
  2. 底层实际上是HashMap

JAVA绘图

定义一个MyPanel类,继承JPanel

重写paint方法,保留里面的super(调用父类有参构造器完成初始化)。Graphics可以理解为画笔类,里面有很多方法

paint会在以下情况下被调用

  1. 组件第一次在屏幕显示
  2. 窗口最小化再最大化
  3. 窗口的大小发生改变
  4. repaint函数被调用

有趣的事情

JDK7新特性,数字直接可以用下划线分割,且不会被输出

int a=10;
int b=20;
System.out.println(""+a+b);
//输出结果为1020;

num--+

输出时"人数为"+num-- +"个",num--意思是每输出一次num-1

split拆分字符串

String[] split = Line.split("=");
//意思是把字符串Line分裂开,分裂的依据是=,分裂的部分会分别放入split数组的各个元素中

在字符串中输入双引号

正常情况下在定义字符串的双引号中写下双引号,\n等会影响字符串输出形式

在“前输入\可以告诉程序这个是字符串的一部分,其他同理

增强for循环

int[] nums = {1,2,9};
for(int i : nums){
	sout(i);
}
//把nums数组一次取出赋给i(跟python的for一样)

三元运算符

Object obj1 = true?new Integer(1) : new Double(2.0);
sout(obj1);
//三元运算符,如果为真选前面,如果为后选后面
//这道题输出的结果为1.0
//三元运算符要看作一个整体,这个整体的最高精度为Double,所以1也是按照double形式输出的
posted @ 2023-01-20 17:39  Zaughter  阅读(52)  评论(0编辑  收藏  举报