Java实习------Java基础2

news2024/9/24 17:20:08

基础语法

基本数据类型 熟悉

Java有哪些数据类型

定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。

byte:

  • byte 数据类型是8位、有符号的,以二进制补码表示的整数;

  • 最小值是 -128(-2^7)

  • 最大值是 127(2^7-1)

  • 默认值是 0

  • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;

  • 例子:byte a = 100,byte b = -50。

short:

  • short 数据类型是 16 位、有符号的以二进制补码表示的整数

  • 最小值是 -32768(-2^15)

  • 最大值是 32767(2^15 - 1)

  • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;

  • 默认值是 0

  • 例子:short s = 1000,short r = -20000。

int:

  • int 数据类型是32位、有符号的以二进制补码表示的整数;

  • 最小值是 -2,147,483,648(-2^31)

  • 最大值是 2,147,483,647(2^31 - 1)

  • 一般地整型变量默认为 int 类型;

  • 默认值是 0

  • 例子:int a = 100000, int b = -200000。

long:

  • long 数据类型是 64 位、有符号的以二进制补码表示的整数;

  • 最小值是 -9,223,372,036,854,775,808(-2^63)

  • 最大值是 9,223,372,036,854,775,807(2^63 -1)

  • 这种类型主要使用在需要比较大整数的系统上;

  • 默认值是 0L

  • 例子: long a = 100000Llong b = -200000L
    "L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。

float:

  • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;

  • float 在储存大型浮点数组的时候可节省内存空间;

  • 默认值是 0.0f

  • 浮点数不能用来表示精确的值,如货币;

  • 例子:float f1 = 234.5f。

double:

  • double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;

  • 浮点数的默认类型为 double 类型;

  • double类型同样不能表示精确的值,如货币;

  • 默认值是 0.0d

boolean:

  • boolean数据类型表示一位的信息;

  • 只有两个取值:true 和 false;

  • 这种类型只作为一种标志来记录 true/false 情况;

  • 默认值是 false

  • 例子:boolean one = true。

char:

  • char 类型是一个单一的 16 位 Unicode 字符;

  • 最小值是 \u0000(十进制等效值为 0);

  • 最大值是 \uffff(即为 65535);

  • char 数据类型可以储存任何字符;

  • 例子:char letter = 'A';。

实际上,JAVA中还存在另外一种基本类型 void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。

类型默认值

下表列出了 Java 各个类型的默认值:

数据类型

默认值

byte

0

short

0

int

0

long

0L

float

0.0f

double

0.0d

char

'u0000'

String (or any object)

null

boolean

false

boolean类型占多少个字节?

  • boolean类型被编译为int类型,等于是说JVM里占用字节和int完全一样,int是4个字节,于是boolean也是4字节

  • boolean数组在Oracle的JVM中,编码为byte数组,每个boolean元素占用8位=1字节(待考证)boolean数组在非Oracle JVM里面,占用字节数也许不是1字节

jdk8的官方文档解释

虽然Java虚拟机定义了一个boolean类型,但它只为它提供了非常有限的支持。没有Java虚拟机指令专门用于对boolean值的操作。相反,Java编程语言中对boolean值进行操作的表达式被编译为使用Java虚拟机int数据类型的值。

Java虚拟机直接支持boolean数组。它的newarray指令可以创建boolean数组。使用byte数组指令baload和bastore访问和修改类型为boolean的数组。

在Oracle的Java虚拟机实现中,Java编程语言中的boolean数组被编码为Java虚拟机byte数组,每个布尔元素使用8位。

Java虚拟机使用1表示boolean数组组件的true,0表示false。其中Java编程语言布尔值由编译器映射到Java虚拟机类型int的值,编译器必须使用相同的编码。

转义字符序列

Java语言支持一些特殊的转义字符序列。

符号

字符含义

\n

换行 (0x0a)

\r

回车 (0x0d)

\f

换页符(0x0c)

\b

退格 (0x08)

\0

空字符 (0x0)

\s

空格 (0x20)

\t

制表符

\"

双引号

\'

单引号

\\

反斜杠

\ddd

八进制字符 (ddd)

\uxxxx

16进制Unicode字符 (xxxx)

自动类型转换

整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。自动类型转换必须满足转换前的数据类型的位数要低于转换后的数据类型,例如: short数据类型的位数为16位,就可以自动转换位数为32的int类型,同样float数据类型的位数为32,可以自动转换为64位的double类型。

转换从低级到高级。
低 ------------------------------------> 高
byte,short,char—> int —> long—> float —> double

数据类型转换必须满足如下规则:

  • 1. 不能对boolean类型进行类型转换。

  • 2. 不能把对象类型转换成不相关类的对象。

  • 3. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。

  • 4. 转换过程中可能导致溢出或损失精度,例如:

int i =128;

byte b = (byte)i;

因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。

  • 5. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:

(int)23.7 == 23;

(int)-45.89f == -45

变量类型 熟悉

变量类型

Java语言支持的变量类型有:

  • 类变量:独立于方法之外的变量,用 static 修饰。

  • 实例变量:独立于方法之外的变量,不过没有 static 修饰。

  • 局部变量:类的方法中的变量。

Java 局部变量

  • 局部变量声明在方法、构造方法或者语句块中;

  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;

  • 访问修饰符不能用于局部变量;

  • 局部变量只在声明它的方法、构造方法或者语句块中可见;

  • 局部变量是在栈上分配的。

  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

实例变量

  • 实例变量声明在一个类中,但在方法、构造方法和语句块之外;

  • 当一个对象被实例化之后,每个实例变量的值就跟着确定;

  • 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;

  • 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;

  • 实例变量可以声明在使用前或者使用后;

  • 访问修饰符可以修饰实例变量;

  • 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;

  • 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;

  • 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObjectReference.VariableName。

类变量(静态变量)

  • 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。

  • 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。

  • 静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变。(public static final String DEPARTMENT = "开发人员";)

  • 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量。

  • 静态变量在第一次被访问时创建,在程序结束时销毁。

  • 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。

  • 默认值和实例变量相似。数值型变量默认值是 0,布尔型默认值是 false,引用类型默认值是 null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。

  • 静态变量可以通过:ClassName.VariableName的方式访问。

  • 类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致。

Java 标识符

Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。

关于 Java 标识符,有以下几点需要注意:

  • 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始

  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合

  • 关键字不能用作标识符

  • 标识符是大小写敏感的

  • 合法标识符举例:age、$salary、_value、__1_value

  • 非法标识符举例:123abc、-salary

修饰符 熟悉

Java修饰符

像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:

  • 访问控制修饰符 : default, public , protected, private

  • 非访问控制修饰符 : final, abstract, static, synchronized

  • 一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。

  • 局部变量不能被声明为 static 变量

  • 抽象类可以包含抽象方法和非抽象方法,抽象方法不能被声明成 final 和 static。抽象方法的声明以分号结尾

  • 任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。

  • 如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。

  • final 定义的类,其中的属性、方法不是 final 的。

public abstract class SuperClass{
    abstract void m(); //抽象方法
}

transient 关键字

Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将二进制数据保存到磁盘或者传输网络,磁盘或者网络接收者可以在对象的属类的模板上来反序列化类的对象,达到对象持久化的目的。

1)transient修饰的变量不能被序列化;

2)transient只作用于实现 Serializable 接口;

3)transient只能用来修饰普通成员变量字段;

4)不管有没有 transient 修饰,静态变量都不能被序列化;

java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。
Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据 成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字 transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的

volatile 修饰符

volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

一个 volatile 对象引用可能是 null。

访问控制修饰符

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。

  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

  • public : 对所有类可见。使用对象:类、接口、变量、方法

  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

我们可以通过以下表来说明访问权限:

访问控制

修饰符

当前类

同一包内

子孙类(同一包)

子孙类(不同包)

其他包

public

Y

Y

Y

Y

Y

protected

Y

Y

Y

Y/N

N

default

Y

Y

Y

N

N

private

Y

N

N

N

N

默认访问修饰符-不使用任何关键字

使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public

私有访问修饰符-private

私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private

声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。

Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据,不能修饰类(内部类除外)。

公有访问修饰符-public

被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问。

如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。

以下函数使用了公有访问控制:

public static void main(String[] arguments) { // ...}

Java 程序的 main() 方法必须设置成公有的,否则,Java 解释器将不能运行该类。

受保护的访问修饰符-protected

protected 需要从以下两个点来分析说明:

  • 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;

  • 子类与基类不在同一包中那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。

protected 可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)。

访问控制和继承

请注意以下方法继承的规则:

  • 父类中声明为 public 的方法在子类中也必须为 public。

  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。

  • 父类中声明为 private 的方法,不能够被子类继承。

运算符 熟悉

算术运算符

表格中的实例整数变量A的值为10,变量B的值为20:

操作符

描述

例子

+

加法 - 相加运算符两侧的值

A + B 等于 30

-

减法 - 左操作数减去右操作数

A – B 等于 -10

*

乘法 - 相乘操作符两侧的值

A * B等于200

/

除法 - 左操作数除以右操作数

B / A等于2

取余 - 左操作数除以右操作数的余数

B%A等于0

++

自增: 操作数的值增加1

B++ 或 ++B 等于 21(区别详见下文)

--

自减: 操作数的值减少1

B-- 或 --B 等于 19(区别详见下文)

关系运算符

表格中的实例整数变量A的值为10,变量B的值为20:

运算符

描述

例子

==

检查如果两个操作数的值是否相等,如果相等则条件为真。

(A == B)为假。

!=

检查如果两个操作数的值是否相等,如果值不相等则条件为真。

(A != B) 为真。

>

检查左操作数的值是否大于右操作数的值,如果是那么条件为真。

(A> B)为假。

<

检查左操作数的值是否小于右操作数的值,如果是那么条件为真。

(A <B)为真。

>=

检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。

(A> = B)为假。

<=

检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。

(A <= B)为真。

位运算符

Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。

位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下:

A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011

下表列出了位运算符的基本运算,假设整数变量 A 的值为 60 和变量 B 的值为 13:

操作符

描述

例子

如果相对应位都是1,则结果为1,否则为0

(A&B),得到12,即0000 1100

|

如果相对应位都是 0,则结果为 0,否则为 1

(A | B)得到61,即 0011 1101

^

如果相对应位值相同,则结果为0,否则为1

(A ^ B)得到49,即 0011 0001

按位取反运算符翻转操作数的每一位,即0变成1,1变成0。

(〜A)得到-61,即1100 0011

<<

按位左移运算符。左操作数按位左移右操作数指定的位数。

A << 2得到240,即 1111 0000

>>

按位右移运算符。左操作数按位右移右操作数指定的位数。

A >> 2得到15即 1111

>>>

按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。

A>>>2得到15即0000 1111

逻辑运算符

下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假

操作符

描述

例子

&&

称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。

(A && B)为假。

| |

称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。

(A | | B)为真。

称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。

!(A && B)为真。

短路逻辑运算符
当使用与逻辑运算符时,在两个操作数都为true时,结果才为true,但是当得到第一个操作为false时,其结果就必定是false,这时候就不会再判断第二个操作了。

赋值运算符

操作符

描述

例子

=

简单的赋值运算符,将右操作数的值赋给左侧操作数

C = A + B将把A + B得到的值赋给C

+ =

加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数

C + = A等价于C = C + A

- =

减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数

C - = A等价于C = C - A

* =

乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数

C * = A等价于C = C * A

/ =

除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数

C / = A,C 与 A 同类型时等价于 C = C / A

(%)=

取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数

C%= A等价于C = C%A

<< =

左移位赋值运算符

C << = 2等价于C = C << 2

>> =

右移位赋值运算符

C >> = 2等价于C = C >> 2

&=

按位与赋值运算符

C&= 2等价于C = C&2

^ =

按位异或赋值操作符

C ^ = 2等价于C = C ^ 2

| =

按位或赋值操作符

C | = 2等价于C = C | 2

其他运算符

条件运算符(?:)

条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。

instanceof 运算符

该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。

instanceof运算符使用格式如下:

( Object reference variable ) instanceof  (class/interface type)

如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。

下面是一个例子:

String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真

如果被比较的对象兼容于右侧类型,该运算符仍然返回 true。

看下面的例子:

class Vehicle {}
 
public class Car extends Vehicle {
   public static void main(String[] args){
      Vehicle a = new Car();
      boolean result =  a instanceof Car;
      System.out.println( result);
   }
}

以上实例编译运行结果如下:

true

Java运算符优先级

类别

操作符

关联性

后缀

() [] . (点操作符)

左到右

一元

expr++ expr--

从左到右

一元

++expr --expr + - ~ !

从右到左

乘性

* /%

左到右

加性

+ -

左到右

移位

>> >>> <<

左到右

关系

> >= < <=

左到右

相等

== !=

左到右

按位与

左到右

按位异或

^

左到右

按位或

|

左到右

逻辑与

&&

左到右

逻辑或

| |

左到右

条件

?:

从右到左

赋值

= + = - = * = / =%= >> = << =&= ^ = | =

从右到左

逗号

左到右

循环结构 熟悉

do…while 循环

对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。

do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

do {
       //代码语句
}while(布尔表达式);//注意最后的;号

注意:布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。 如果布尔表达式的值为 true,则语句块一直执行,直到布尔表达式的值为 false。

for循环

虽然所有循环结构都可以用 while 或者 do...while表示,但 Java 提供了另一种语句 —— for 循环,使一些循环结构变得更加简单。

for循环执行的次数是在执行前就确定的。语法格式如下:

for(初始化; 布尔表达式; 更新) {    
   //代码语句
}

关于 for 循环有以下几点说明:

  • 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。

  • 然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。

  • 执行一次循环后,更新循环控制变量。

  • 再次检测布尔表达式。循环执行上面的过程。

Java 增强 for 循环

Java5 引入了一种主要用于数组的增强型 for 循环。

Java 增强 for 循环语法格式如下:

for(声明语句 : 表达式){   //代码句子}

声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。

表达式:表达式是要访问的数组名,或者是返回值为数组的方法。

public class Test {
   public static void main(String[] args){
      int [] numbers = {10, 20, 30, 40, 50};
 
      for(int x : numbers ){
         System.out.print( x );
         System.out.print(",");
      }
      System.out.print("\n");
      String [] names ={"James", "Larry", "Tom", "Lacy"};
      for( String name : names ) {
         System.out.print( name );
         System.out.print(",");
      }
   }
}

break、continue、return 的区别

  • break默认是跳出最里层的循环,也就是break所在的最近的那层循环

  • continue是终止本次循环,继续下次循环

  • return 结束当前方法

数组 熟悉

一维数组

正确创建数组的方法:

  • new对象型,并指定初始长度

  • int[ ] arr = new int[5]; // 创建长度为5 的数组

  • 直接初始化特定值型

  • int[ ] arr = {1,2,3,4};

  • new对象+初始化值型

  • int[ ] arr = new int[]{1,2,3,4}

二维数组

正确创建数组的方法:

  • Java创建二维数组

  • int [][] array = new int[6][6];

  • 直接创建二维数组并赋值

  • int [][] array = {{1,2,3},{1,2,3},{1,2,3}};

  • int [][] array = new int[6][];

String[][] s = new String[2][];
s[0] = new String[2];
s[1] = new String[3];
s[0][0] = new String("Good");
s[0][1] = new String("Luck");
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");

解析

s[0]=new String[2] 和 s[1]=new String[3] 是为最高维分配引用空间,也就是为最高维限制其能保存数据的最长的长度,然后再为其每个数组元素单独分配空间 s0=new String("Good") 等操作。

Arrays 类

java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。

具有以下功能:

  • 给数组赋值:通过 fill 方法。

  • 对数组排序:通过 sort 方法,按升序。

  • 比较数组:通过 equals 方法比较数组中元素值是否相等。

  • 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。

具体说明请查看下表:

序号

方法和说明

1

public static int binarySearch(Object[] a, Object key)

用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。

2

public static boolean equals(long[] a, long[] a2)

如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。

3

public static void fill(int[] a, int val)

将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。

4

public static void sort(Object[] a)

对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。

面向对象

什么是抽象 熟悉

抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

Java 抽象类

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

public abstract class Employee
{
   private String name;
   private String address;
   private int number;
   public Employee(String name, String address, int number)
   {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   public double computePay()
   {
     System.out.println("Inside Employee computePay");
     return 0.0;
   }
   public void mailCheck()
   {
      System.out.println("Mailing a check to " + this.name
       + " " + this.address);
   }
   public String toString()
   {
      return name + " " + address + " " + number;
   }
   public String getName()
   {
      return name;
   }
   public String getAddress()
   {
      return address;
   }
   public void setAddress(String newAddress)
   {
      address = newAddress;
   }
   public int getNumber()
   {
     return number;
   }
}

注意到该 Employee 类没有什么不同,尽管该类是抽象类,但是它仍然有 3 个成员变量,7 个成员方法和 1 个构造方法。 现在如果你尝试如下的例子:

public class AbstractDemo
{
   public static void main(String [] args)
   {
      /* 以下是不允许的,会引发错误 */
      Employee e = new Employee("George W.", "Houston, TX", 43);
 
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
    }
}

当你尝试编译 AbstractDemo 类时,会产生如下错误:

Employee.java:46: Employee is abstract; cannot be instantiated
      Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error

我们可以通过以下方式继承 Employee 类的属性:

public class Salary extends Employee
{
   private double salary; //Annual salary
   public Salary(String name, String address, int number, double
      salary)
   {
       super(name, address, number);
       setSalary(salary);
   }
   public void mailCheck()
   {
       System.out.println("Within mailCheck of Salary class ");
       System.out.println("Mailing check to " + getName()
       + " with salary " + salary);
   }
   public double getSalary()
   {
       return salary;
   }
   public void setSalary(double newSalary)
   {
       if(newSalary >= 0.0)
       {
          salary = newSalary;
       }
   }
   public double computePay()
   {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}

尽管我们不能实例化一个 Employee 类的对象,但是如果我们实例化一个 Salary 类对象,该对象将从 Employee 类继承 7 个成员方法,且通过该方法可以设置或获取三个成员变量。

public class AbstractDemo
{
   public static void main(String [] args)
   {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
 
      System.out.println("Call mailCheck using Salary reference --");
      s.mailCheck();
 
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
    }
}

以上程序编译运行结果如下:

Constructing an Employee
Constructing an Employee
Call mailCheck using  Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.

抽象类总结规定

1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

4. 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。

5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

什么是封装 熟悉

隐藏对象的属性和实现细节同时提供一些可以被外界访问的属性的方法

什么是继承 熟悉

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。

关于继承的要点:

  • 子类拥有父类非 private 的属性和方法。

  • 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

  • 子类可以用自己的方式实现父类的方法(重写)。

  • 子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。

什么是多态 熟悉

多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作

多态存在的三个必要条件

  • 继承

  • 重写

  • 父类引用指向子类对象:Parent p = new Child();

当使用多态方式调用方法时(也就是向上转型),首先检查父类中是否有该方法,如果没有,则编译错误(如上所示爆红了);如果有,再去调用子类的同名方法。

内部类的使用 熟悉

内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。

1、静态内部类

定义在类内部的静态类,就是静态内部类。

public class Outer {
      private static int radius =1;
       //静态内部类
static class StaticInner{ 
public void visit(){
    System.out.println("visit outer static variable:"+ radius);
    }
  }
}

静态内部类可以访问外部类所有的静态变量,但是不可访问外部类的非静态变量;

静态内部类的创建方式,new 外部类.静态内部类(),如下:

Outer.StaticInner inner =new Outer.StaticInner();
 
inner.visit();

2、成员内部类

定义在类内部,成员位置上的非静态类,就是成员内部类。

public class Outer {
private static int radius =1;
privateint count =2;
class Inner{
public void visit(){    
System.out.println("visit outer static  variable:"+ radius);    
System.out.println("visit outer variable:"+ count);
      }
   }
}

成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。

成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类(),如下:

Outer outer =new Outer();
 
Outer.Inner inner = outer.new Inner();
 
inner.visit();

3、局部内部类

定义在方法中的内部类,就是局部内部类。

public class Outer{
    private int out_a =1;
    private static int STATIC_b =2;
    public void test FunctionClass(){
        int inner_c=3;
        class Inner{
            private void fun(){        
                System.out.println(out_a);    
                System.out.println(STATIC_b); 
                System.out.println(inner_c);
                }
             }    
                Inner  inner =new Inner();    //直接在方法里用new创建局部内部类
                inner.fun();
           }
 
        public static void test StaticFunctionClass(){
            int d=3;
            class Inner{
                private void fun(){
                    //System.out.println(out_a); 
                    //编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
                    System.out.println(STATIC_b);    
                    System.out.println(d);
                    }
                }    
                    Inner  inner =new Inner();    //直接在方法里用new创建局部内部类
                    inner.fun();
      }
} 

定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和静态方法 。

局部内部类的创建方式 ,在对应方法内 new 内部类(), 如下 :

public static void testStaticFunctionClass(){
  class Inner{} 
  Inner inner =new Inner();
}

4、匿名内部类

匿名内部类就是没有名字的内部类

匿名内部类举例

红色框画出来的就是一个匿名内部类同时重写了父类Animals的eat方法,并且调用了这个匿名内部类的eat方法

如何调用匿名内部类中的方法?

1、匿名内部类中只有一个方法的情况

2、匿名内部类有多个方法

第一种方式

第二种方式

如果想调用匿名内部类自己特有的方法的时候呢?该如何调用呢?

匿名内部类可以有自己特有的方法,但是前提条件是这个匿名内部类只有这一个方法(不重写父类或者接口的方法)。如果有多个方法的时候,他只能继承父类的方法以及重写这个方法或实现接口,绝不可能在在多个方法的情况下,调用自身特有的方法,但是这个特有的方法可以存在,但无法调用

匿名内部类是实现接口

匿名内部类的特点

除了没有名字,匿名内部类还有以下特点:

1、匿名内部类必须继承一个抽象类或者实现一个接口。

2、匿名内部类不能定义任何静态成员和静态方法。

3、匿名内部类访问局部变量的时候,必须把局部变量声明为 final。

4、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

匿名内部类创建方式:

new 类/接口{

//匿名内部类实现部分

}

重载与重写的区别 熟悉

重载与重写的区别

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

  • (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。

  • (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。

  • (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

重写(Override)

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。

在面向对象原则里,重写意味着可以重写任何现有方法。

方法的重写规则

  • 参数列表与被重写方法的参数列表必须完全相同。

  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。

  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。

  • 父类的成员方法只能被它的子类重写。

  • 声明为 final 的方法不能被重写。

  • 声明为 static 的方法不能被重写,但是能够被再次声明

  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。

  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。

  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。

  • 构造方法不能被重写。

  • 如果不能继承一个类,则不能重写该类的方法。

重载(Overload)

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。

每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。

最常用的地方就是构造器的重载。

重载规则

  • 被重载的方法必须改变参数列表(参数个数或类型不一样);

  • 被重载的方法可以改变返回类型;

  • 被重载的方法可以改变访问修饰符;

  • 被重载的方法可以声明新的或更广的检查异常;

  • 方法能够在同一个类中或者在一个子类中被重载。

  • 无法以返回值类型作为重载函数的区分标准。

什么是枚举 熟悉

Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。

Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。

enum Color
{
    RED, GREEN, BLUE;
}
 
public class Test
{
    // 执行输出结果
    public static void main(String[] args)
    {
        Color c1 = Color.RED;
        System.out.println(c1);
    }
}

values(), ordinal() 和 valueOf() 方法

enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。

values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:

  • values() 返回枚举类中所有的值。

  • ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样(也是从0开始)。

  • valueOf()方法返回指定字符串值的枚举常量。

枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。

枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。

enum Color
{
    RED, GREEN, BLUE;
 
    // 构造函数
    private Color()
    {
        System.out.println("Constructor called for : " + this.toString());
    }
 
    public void colorInfo()
    {
        System.out.println("Universal Color");
    }
}
 
public class Test
{    
    // 输出
    public static void main(String[] args)
    {
        Color c1 = Color.RED;
        System.out.println(c1);
        c1.colorInfo();
    }
}

数据结构

集合整体架构 了解

Java提供了一套实现了Collection接口的标准集合类。其中一些是具体类,这些类可以直接拿来使用,而另外一些是抽象类,提供了接口的部分实现。

标准集合类汇总于下表:

序号

类描述

1

AbstractCollection

实现了大部分的集合接口。

2

AbstractList

继承于AbstractCollection 并且实现了大部分List接口。

3

AbstractSequentialList

继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问。

4

LinkedList

该类实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List。例如:

List list=Collections.synchronizedList(newLinkedList(...));

LinkedList 查找效率低。

5

ArrayList

该类也是实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的情况下不要使用。ArrayList 增长当前长度的50%,插入删除效率低。

6

AbstractSet

继承于AbstractCollection 并且实现了大部分Set接口。

7

HashSet

该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。

8

LinkedHashSet

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。

9

TreeSet

该类实现了Set接口,可以实现排序等功能。

10

AbstractMap

实现了大部分的Map接口。

11

HashMap

HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

该类实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。

12

TreeMap

继承了AbstractMap,并且使用一颗树。

13

WeakHashMap

继承AbstractMap类,使用弱密钥的哈希表。

14

LinkedHashMap

继承于HashMap,使用元素的自然顺序对元素进行排序.

15

IdentityHashMap

继承AbstractMap类,比较文档时使用引用相等。

在java.util包中定义的类,如下所示:

序号

类描述

1

Vector

该类和ArrayList非常相似,但是该类是同步的,可以用在多线程的情况,该类允许设置默认的增长长度,默认扩容方式为原来的2倍。

2

Stack

栈是Vector的一个子类,它实现了一个标准的后进先出的栈。

3

Dictionary

Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。

4

Hashtable

Hashtable 是 Dictionary(字典) 类的子类,位于 java.util 包中。

5

Properties

Properties 继承于 Hashtable,表示一个持久的属性集,属性列表中每个键及其对应值都是一个字符串。

6

BitSet

一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。

遍历 Map

import java.util.*;
 
public class Test{
     public static void main(String[] args) {
      Map<String, String> map = new HashMap<String, String>();
      map.put("1", "value1");
      map.put("2", "value2");
      map.put("3", "value3");
      
      //第一种:普遍使用,二次取值
      System.out.println("通过Map.keySet遍历key和value:");
      for (String key : map.keySet()) {
       System.out.println("key= "+ key + " and value= " + map.get(key));
      }
      
      //第二种
      System.out.println("通过Map.entrySet使用iterator遍历key和value:");
      Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
      while (it.hasNext()) {
       Map.Entry<String, String> entry = it.next();
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
      
      //第三种:推荐,尤其是容量大时
      System.out.println("通过Map.entrySet遍历key和value");
      for (Map.Entry<String, String> entry : map.entrySet()) {
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
    
      //第四种
      System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
      for (String v : map.values()) {
       System.out.println("value= " + v);
      }
     }
}

字典的结构 了解

Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。

给出键和值,你就可以将值存储在Dictionary对象中。一旦该值被存储,就可以通过它的键来获取它。所以和Map一样, Dictionary 也可以作为一个键/值对列表。

Dictionary定义的抽象方法如下表所示:

序号

方法描述

1

Enumeration elements( )

返回此 dictionary 中值的枚举。

2

Object get(Object key)

返回此 dictionary 中该键所映射到的值。

3

boolean isEmpty( )

测试此 dictionary 是否不存在从键到值的映射。

4

Enumeration keys( )

返回此 dictionary 中的键的枚举。

5

Object put(Object key, Object value)

将指定 key 映射到此 dictionary 中指定 value。

6

Object remove(Object key)

从此 dictionary 中移除 key (及其相应的 value)。

7

int size( )

返回此 dictionary 中条目(不同键)的数量。

Dictionary类已经过时了。在实际开发中,你可以实现Map接口来获取键/值的存储功能。

栈的结构 了解

Java中Stack 栈是Vector的一个子类,它实现了一个标准的后进先出的栈。

堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。

序号

方法描述

1

boolean empty()

测试堆栈是否为空。

2

Object peek( )

查看堆栈顶部的对象,但不从堆栈中移除它。

3

Object pop( )

移除堆栈顶部的对象,并作为此函数的值返回该对象。

4

Object push(Object element)

把项压入堆栈顶部。

5

int search(Object element)

返回对象在堆栈中的位置,以 1 为基数。

哈希表的结构 了解

Hashtable是原始的java.util的一部分, 是一个Dictionary具体的实现 。

然而,Java 2 重构的Hashtable实现了Map接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步。

像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。

然后,该键经过哈希处理,所得到的散列码被用作存储在该表中值的索引。

Hashtable中除了从Map接口中定义的方法外,还定义了以下方法:

序号

方法描述

1

void clear( )

将此哈希表清空,使其不包含任何键。

2

Object clone( )

创建此哈希表的浅表副本。

3

boolean contains(Object value)

测试此映射表中是否存在与指定值关联的键。

4

boolean containsKey(Object key)

测试指定对象是否为此哈希表中的键。

5

boolean containsValue(Object value)

如果此 Hashtable 将一个或多个键映射到此值,则返回 true。

6

Enumeration elements( )

返回此哈希表中的值的枚举。

7

Object get(Object key)

返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,则此方法返回 v;否则,返回 null。

8

boolean isEmpty( )

测试此哈希表是否没有键映射到值。

9

Enumeration keys( )

返回此哈希表中的键的枚举。

10

Object put(Object key, Object value)

将指定 key 映射到此哈希表中的指定 value。

11

void rehash( )

增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。

12

Object remove(Object key)

从哈希表中移除该键及其相应的值。

13

int size( )

返回此哈希表中的键的数量。

14

String toString( )

返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 ", " (逗号加空格)分隔开的、括在括号中的一组条目。

Properties 的使用 了解

Properties 继承于 Hashtable。表示一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。

Properties 类被许多 Java 类使用。例如,在获取环境变量时它就作为 System.getProperties() 方法的返回值。

除了从 Hashtable 中所定义的方法,Properties 还定义了以下方法:

序号

方法描述

1

String getProperty(String key)

用指定的键在此属性列表中搜索属性。

2

String getProperty(String key, String defaultProperty)

用指定的键在属性列表中搜索属性。

3

void list(PrintStream streamOut)

将属性列表输出到指定的输出流。

4

void list(PrintWriter streamOut)

将属性列表输出到指定的输出流。

5

void load(InputStream streamIn) throws IOException

从输入流中读取属性列表(键和元素对)。

6

Enumeration propertyNames( )

按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

7

Object setProperty(String key, String value)

调用 Hashtable 的方法 put。

8

void store(OutputStream streamOut, String description)

以适合使用 load(InputStream)方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。

集合与泛型

ArrayList 的使用 熟悉

Java ArrayList 常用方法列表如下:

方法

描述

add()

将元素插入到指定位置的 arraylist 中

addAll()

添加集合中的所有元素到 arraylist 中

clear()

删除 arraylist 中的所有元素

clone()

复制一份 arraylist

contains()

判断元素是否在 arraylist

get()

通过索引值获取 arraylist 中的元素

indexOf()

返回 arraylist 中元素的索引值

removeAll()

删除存在于指定集合中的 arraylist 里的所有元素

remove()

删除 arraylist 里的单个元素

size()

返回 arraylist 里元素数量

isEmpty()

判断 arraylist 是否为空

subList()

截取部分 arraylist 的元素

set()

替换 arraylist 中指定索引的元素

sort()

对 arraylist 元素进行排序

toArray()

将 arraylist 转换为数组

toString()

将 arraylist 转换为字符串

ensureCapacity()

设置指定容量大小的 arraylist

lastIndexOf()

返回指定元素在 arraylist 中最后一次出现的位置

retainAll()

保留 arraylist 中在指定集合中也存在的那些元素

containsAll()

查看 arraylist 是否包含指定集合中的所有元素

trimToSize()

将 arraylist 中的容量调整为数组中的元素个数

removeRange()

删除 arraylist 中指定索引之间存在的元素

replaceAll()

将给定的操作内容替换掉数组中每一个元素

removeIf()

删除所有满足特定条件的 arraylist 元素

forEach()

遍历 arraylist 中每一个元素并执行特定操作

LinkedList 的使用 熟悉

方法

描述

public boolean add(E e)

链表末尾添加元素,返回是否成功,成功为 true,失败为 false。

public void add(int index, E element)

向指定位置插入元素。

public boolean addAll(Collection c)

将一个集合的所有元素添加到链表后面,返回是否成功,成功为 true,失败为 false。

public boolean addAll(int index, Collection c)

将一个集合的所有元素添加到链表的指定位置后面,返回是否成功,成功为 true,失败为 false。

public void addFirst(E e)

元素添加到头部。

public void addLast(E e)

元素添加到尾部。

public boolean offer(E e)

向链表末尾添加元素,返回是否成功,成功为 true,失败为 false。

public boolean offerFirst(E e)

头部插入元素,返回是否成功,成功为 true,失败为 false。

public boolean offerLast(E e)

尾部插入元素,返回是否成功,成功为 true,失败为 false。

public void clear()

清空链表。

public E removeFirst()

删除并返回第一个元素。

public E removeLast()

删除并返回最后一个元素。

public boolean remove(Object o)

删除某一元素,返回是否成功,成功为 true,失败为 false。

public E remove(int index)

删除指定位置的元素。

public E poll()

删除并返回第一个元素。

public E remove()

删除并返回第一个元素。

public boolean contains(Object o)

判断是否含有某一元素。

public E get(int index)

返回指定位置的元素。

public E getFirst()

返回第一个元素。

public E getLast()

返回最后一个元素。

public int indexOf(Object o)

查找指定元素从前往后第一次出现的索引。

public int lastIndexOf(Object o)

查找指定元素最后一次出现的索引。

public E peek()

返回第一个元素。

public E element()

返回第一个元素。

public E peekFirst()

返回头部元素。

public E peekLast()

返回尾部元素。

public E set(int index, E element)

设置指定位置的元素。

public Object clone()

克隆该列表。

public Iterator descendingIterator()

返回倒序迭代器。

public int size()

返回链表元素个数。

public ListIterator listIterator(int index)

返回从指定位置开始到末尾的迭代器。

public Object[] toArray()

返回一个由链表元素组成的数组。

public T[] toArray(T[] a)

返回一个由链表元素转换类型而成的数组。

HashSet 的使用 熟悉

HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。

HashSet 允许有 null 值。

HashSet 是无序的,即不会记录插入的顺序。

HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。

HashSet 实现了 Set 接口。

变量和类型

方法

描述

boolean

add​(E e)

如果指定的元素尚不存在,则将其添加到此集合中。

void

clear()

从该集中删除所有元素。

Object

clone()

返回此 HashSet实例的浅表副本:未克隆元素本身。

boolean

contains​(Object o)

如果此set包含指定的元素,则返回 true 。

boolean

isEmpty()

如果此集合不包含任何元素,则返回 true 。

Iterator<E>

iterator()

返回此set中元素的迭代器。

boolean

remove​(Object o)

如果存在,则从该集合中移除指定的元素。

int

size()

返回此集合中的元素数(基数)。

Spliterator<E>

spliterator()

在此集合中的元素上创建late-binding失败快速 Spliterator 。

TreeSet 的使用 熟悉

TreeSet 是一个有序的集合,它的作用是提供有序的Set集合。它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, java.io.Serializable接口。

TreeSet 继承于AbstractSet,所以它是一个Set集合,具有Set的属性和方法。

TreeSet 实现了NavigableSet接口,意味着它支持一系列的导航方法。比如查找与指定目标最匹配项。

TreeSet 实现了Cloneable接口,意味着它能被克隆。

TreeSet 实现了java.io.Serializable接口,意味着它支持序列化。

TreeSet是基于TreeMap实现的。TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。

TreeSet为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销。

另外,TreeSet是非同步的。 它的iterator 方法返回的迭代器是fail-fast的。

常用方法API

变量和类型

方法

描述

boolean

add​(E e)

如果指定的元素尚不存在,则将其添加到此集合中。

boolean

addAll​(Collection<? extends E> c)

将指定集合中的所有元素添加到此集合中。

E

ceiling​(E e)

返回此set中大于或等于给定元素的 null元素,如果没有这样的元素,则 null 。

void

clear()

从该集中删除所有元素。

Object

clone()

返回此 TreeSet实例的浅表副本。

boolean

contains​(Object o)

如果此set包含指定的元素,则返回 true 。

Iterator<E>

descendingIterator()

以降序返回此集合中元素的迭代器。

NavigableSet<E>

descendingSet()

返回此set中包含的元素的逆序视图。

E

first()

返回此集合中当前的第一个(最低)元素。

E

floor​(E e)

返回此set中小于或等于给定元素的最大元素,如果没有这样的元素,则 null 。

SortedSet<E>

headSet​(E toElement)

返回此set的部分视图,其元素严格小于 toElement 。

NavigableSet<E>

headSet​(E toElement, boolean inclusive)

返回此set的部分视图,其元素小于(或等于,如果 inclusive为true) toElement 。

E

higher​(E e)

返回此集合中的最小元素严格大于给定元素,如果没有这样的元素,则 null 。

boolean

isEmpty()

如果此集合不包含任何元素,则返回 true 。

Iterator<E>

iterator()

以升序返回此集合中元素的迭代器。

E

last()

返回此集合中当前的最后一个(最高)元素。

E

lower​(E e)

返回此集合中的最大元素严格小于给定元素,如果没有这样的元素,则 null 。

E

pollFirst()

检索并删除第一个(最低)元素,如果此组为空,则返回 null 。

E

pollLast()

检索并删除最后一个(最高)元素,如果此集合为空,则返回 null 。

boolean

remove​(Object o)

如果存在,则从该集合中移除指定的元素。

int

size()

返回此集合中的元素数(基数)。

Spliterator<E>

spliterator()

在此集合中的元素上创建late-binding故障快速 Spliterator 。

NavigableSet<E>

subSet​(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)

返回此set的部分视图,其元素范围为 fromElement到 toElement 。

SortedSet<E>

subSet​(E fromElement, E toElement)

返回此set的部分视图,其元素范围从 fromElement (含)到 toElement (独占)。

SortedSet<E>

tailSet​(E fromElement)

返回此set的部分视图,其元素大于或等于 fromElement 。

NavigableSet<E>

tailSet​(E fromElement, boolean inclusive)

返回此set的部分视图,其元素大于(或等于,如果 inclusive为true) fromElement 。

HashMap 的使用 熟悉

HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。

HashMap 是无序的,即不会记录插入的顺序。

HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。

HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(String)类型的 key 和 value,也可以是整型(Integer)的 key 和字符串(String)类型的 value。

如果你只想获取 key,可以使用 keySet() 方法,然后可以通过 get(key) 获取对应的 value,如果你只想获取 value,可以使用 values() 方法。

import java.util.HashMap;

public class RunoobTest {
    public static void main(String[] args) {
        // 创建 HashMap 对象 Sites
        HashMap<Integer, String> Sites = new HashMap<Integer, String>();
        // 添加键值对
        Sites.put(1, "Google");
        Sites.put(2, "Runoob");
        Sites.put(3, "Taobao");
        Sites.put(4, "Zhihu");
        // 输出 key 和 value
        for (Integer i : Sites.keySet()) {
            System.out.println("key: " + i + " value: " + Sites.get(i));
        }
        // 返回所有 value 值
        for(String value: Sites.values()) {
          // 输出每一个value
          System.out.print(value + ", ");
        }
    }
}

Java HashMap 常用方法列表如下:

方法

描述

clear()

删除 hashMap 中的所有键/值对

clone()

复制一份 hashMap

isEmpty()

判断 hashMap 是否为空

size()

计算 hashMap 中键/值对的数量

put()

将键/值对添加到 hashMap 中

putAll()

将所有键/值对添加到 hashMap 中

putIfAbsent()

如果 hashMap 中不存在指定的键,则将指定的键/值对插入到 hashMap 中。

remove()

删除 hashMap 中指定键 key 的映射关系

containsKey()

检查 hashMap 中是否存在指定的 key 对应的映射关系。

containsValue()

检查 hashMap 中是否存在指定的 value 对应的映射关系。

replace()

替换 hashMap 中是指定的 key 对应的 value。

replaceAll()

将 hashMap 中的所有映射关系替换成给定的函数所执行的结果。

get()

获取指定 key 对应对 value

getOrDefault()

获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值

forEach()

对 hashMap 中的每个映射执行指定的操作。

entrySet()

返回 hashMap 中所有映射项的集合集合视图。

keySet()

返回 hashMap 中所有 key 组成的集合视图。

values()

返回 hashMap 中存在的所有 value 值。

merge()

添加键值对到 hashMap 中

compute()

对 hashMap 中指定 key 的值进行重新计算

computeIfAbsent()

对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hasMap 中

computeIfPresent()

对 hashMap 中指定 key 的值进行重新计算,前提是该 key 存在于 hashMap 中。

TreeMap 的使用 熟悉

变量和类型

方法

描述

Map.Entry<K,​V>

ceilingEntry​(K key)

返回与大于或等于给定键的最小键关联的键 - 值映射,如果没有此键,则 null 。

K

ceilingKey​(K key)

返回大于或等于给定键的 null键,如果没有这样的键,则 null 。

void

clear()

从此映射中删除所有映射。

Object

clone()

返回此 TreeMap实例的浅表副本。

boolean

containsKey​(Object key)

如果此映射包含指定键的映射,则返回 true 。

boolean

containsValue​(Object value)

如果此映射将一个或多个键映射到指定值,则返回 true 。

NavigableSet<K>

descendingKeySet()

返回此映射中包含的键的反向顺序NavigableSet视图。

NavigableMap<K,​V>

descendingMap()

返回此映射中包含的映射的逆序视图。

Set<Map.Entry<K,​V>>

entrySet()

返回此映射中包含的映射的Set视图。

Map.Entry<K,​V>

firstEntry()

返回与此映射中的最小键关联的键 - 值映射,如果映射为空,则 null 。

K

firstKey()

返回此映射中当前的第一个(最低)键。

Map.Entry<K,​V>

floorEntry​(K key)

返回与小于或等于给定键的最大键关联的键 - 值映射,如果没有此键,则 null 。

K

floorKey​(K key)

返回小于或等于给定键的最大键,如果没有这样的键,则 null 。

V

get​(Object key)

返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。

SortedMap<K,​V>

headMap​(K toKey)

返回此映射的部分视图,其键严格小于 toKey 。

NavigableMap<K,​V>

headMap​(K toKey, boolean inclusive)

返回此映射的部分视图,其键小于(或等于,如果 inclusive为真) toKey 。

Map.Entry<K,​V>

higherEntry​(K key)

返回与严格大于给定键的最小键关联的键 - 值映射,如果没有此键,则 null 。

K

higherKey​(K key)

返回严格大于给定键的最小键,如果没有这样的键,则返回 null 。

Set<K>

keySet()

返回此映射中包含的键的Set视图。

Map.Entry<K,​V>

lastEntry()

返回与此映射中的最大键关联的键 - 值映射,如果映射为空,则 null 。

K

lastKey()

返回此映射中当前的最后一个(最高)键。

Map.Entry<K,​V>

lowerEntry​(K key)

返回与严格小于给定键的最大键相关联的键 - 值映射,如果没有这样的键,则 null 。

K

lowerKey​(K key)

返回严格小于给定键的最大键,如果没有这样键,则返回 null 。

NavigableSet<K>

navigableKeySet()

返回此映射中包含的键的NavigableSet视图。

Map.Entry<K,​V>

pollFirstEntry()

删除并返回与此映射中的最小键关联的键 - 值映射,如果映射为空,则 null 。

Map.Entry<K,​V>

pollLastEntry()

删除并返回与此映射中的最大键关联的键 - 值映射,如果映射为空,则 null 。

V

put​(K key, V value)

将指定的值与此映射中的指定键相关联。

void

putAll​(Map<? extends K,​? extends V> map)

将指定映射中的所有映射复制到此映射。

V

remove​(Object key)

如果存在,则从此TreeMap中删除此键的映射。

int

size()

返回此映射中键 - 值映射的数量。

NavigableMap<K,​V>

subMap​(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)

返回此映射部分的视图,其键范围为 fromKey至 toKey 。

SortedMap<K,​V>

subMap​(K fromKey, K toKey)

返回此映射部分的视图,其键的范围从 fromKey (包括 toKey )到 toKey (独占)。

SortedMap<K,​V>

tailMap​(K fromKey)

返回此映射的部分视图,其键大于或等于 fromKey 。

NavigableMap<K,​V>

tailMap​(K fromKey, boolean inclusive)

返回此映射的部分视图,其键大于(或等于,如果 inclusive为真) fromKey 。

Collection<V>

values()

返回此映射中包含的值的Collection视图。

反射

反射机制和原理 了解

好文参考:https://zhuanlan.zhihu.com/p/162971344

获取和操作构造器、方法、属性 了解

好文参考:https://cloud.tencent.com/developer/article/1946432

异常

Throwable 是 Java 语言中所有错误与异常的超类。

Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示发生了异常情况。

Throwable 包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace() 等接口用于获取堆栈跟踪数据等信息。

Exception(异常)是程序本身可以捕获并且可以处理的异常。

  • 运行时异常是非受检异常,是RuntimeException的子类,即编译器无法检测,因此也不会强制要求程序员处理。

  • 编译时异常是受检异常,编译器检测到代码抛出编译时异常时,会要求程序员必须对该异常做处理(throws或try…catch)否则,编译不通过。

受检查异常的理解和使用 熟悉

定义: Exception 中除 RuntimeException 及其子类之外的异常。

特点: Java 编译器会检查它。如果程序中出现此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。该异常我们必须手动在代码里添加捕获语句来处理该异常。

常见的编译时异常:

  • IO操作异常:IOException

  • 文件找不到异常:FileNotFoundException

  • 类找不到异常:ClassNotFoundException

  • 没有对应的方法异常:NoSuchMethodException

  • 已到达文件流末尾异常:EOFException

运行时异常的理解和使用 熟悉

定义:RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。

特点:Java编译器不会检查它。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws 声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。

常见的运行时异常:

  • NullPointerException 空指针异常

  • ArrayIndexOutBoundException 数组下标越界异常

  • ClassCastException 类型转换异常

  • ArithmeticExecption 算术异常

此类异常属于不受检异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。虽然 Java 编译器不会检查运行时异常,但是我们也可以通过throws 进行声明抛出,也可以通过 try-catch 对它进行捕获处理。如果产生运行时异常,则需要通过修改代码来进行避免。例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生! RuntimeException 异常会由 Java 虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也会抛出错误!!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。

错误 ERROR 的理解 了解

定义:Error 类及其子类。程序中无法处理的错误,表示运行应用程序中出现了严重的错误。

特点:此类错误一般表示代码运行时 JVM 出现问题。

常见的Error错误如下:

  • Virtual MachineError(虚拟机运行错误)

  • NoClassDefFoundError(类定义错误)

  • OutOfMemoryError:内存不足错误

  • StackOverflowError:栈溢出错误。

此类错误发生时,JVM 将终止线程。

这些错误是不受检异常,非代码性错误。因此,当此类错误发生时,应用程序不应该去处理此类错误。按照Java惯例,我们是不应该实现任何新的Error子类的!

常用工具类

日期相关 熟悉

Date 对象创建以后,可以调用下面的方法。

序号

方法和描述

1

boolean after(Date date)

若当调用此方法的Date对象在指定日期之后返回true,否则返回false。

2

boolean before(Date date)

若当调用此方法的Date对象在指定日期之前返回true,否则返回false。

3

Object clone( )

返回此对象的副本。

4

int compareTo(Date date)

比较当调用此方法的Date对象和指定日期。两者相等时候返回0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数。

5

int compareTo(Object obj)

若obj是Date类型则操作等同于compareTo(Date) 。否则它抛出ClassCastException。

6

boolean equals(Object date)

当调用此方法的Date对象和指定日期相等时候返回true,否则返回false。

7

long getTime( )

返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

8

int hashCode( )

返回此对象的哈希码值。

9

void setTime(long time)

用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。

10

String toString( )

把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。

日期比较

Java使用以下三种方法来比较两个日期:

  • 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。

  • 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true。

  • 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。

使用 SimpleDateFormat 格式化日期

SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat 允许你选择任何用户自定义日期时间格式来运行。例如:

import  java.util.*;
import java.text.*;
 
public class DateDemo {
   public static void main(String[] args) {
 
      Date dNow = new Date( );
      SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
 
      System.out.println("当前时间为: " + ft.format(dNow));
   }
}
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");

这一行代码确立了转换的格式,其中 yyyy 是完整的公元年,MM 是月份,dd 是日期,HH:mm:ss 是时、分、秒。

注意:有的格式大写,有的格式小写,例如 MM 是月份,mm 是分;HH 是 24 小时制,而 hh 是 12 小时制。

以上实例编译运行结果如下:

当前时间为: 2018-09-06 10:16:34

日期和时间的格式化编码

时间模式字符串用来指定时间格式。在此模式中,所有的 ASCII 字母被保留为模式字母,定义如下:

字母

描述

示例

G

纪元标记

AD

y

四位年份

2001

M

月份

July or 07

d

一个月的日期

10

h

A.M./P.M. (1~12)格式小时

12

H

一天中的小时 (0~23)

22

m

分钟数

30

s

秒数

55

S

毫秒数

234

E

星期几

Tuesday

D

一年中的日子

360

F

一个月中第几周的周几

2 (second Wed. in July)

w

一年中第几周

40

W

一个月中第几周

1

a

A.M./P.M. 标记

PM

k

一天中的小时(1~24)

24

K

A.M./P.M. (0~11)格式小时

10

z

时区

Eastern Standard Time

'

文字定界符

Delimiter

"

单引号

`

Calendar类

我们现在已经能够格式化并创建一个日期对象了,但是我们如何才能设置和获取日期数据的特定部分呢,比如说小时,日,或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类。

Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要复杂一些。

Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可。

创建一个代表系统当前日期的Calendar对象

Calendar c = Calendar.getInstance();//默认是当前日期

创建一个指定日期的Calendar对象

使用Calendar类代表特定的时间,需要首先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。

//创建一个代表2009年6月12日的Calendar对象
Calendar c1 = Calendar.getInstance();
c1.set(2009, 6 , 12); //int year,int month,int date

Calendar类对象字段类型

Calendar类中用以下这些常量表示不同的意义,jdk内的很多类其实都是采用的这种思想

常量

描述

Calendar.YEAR

年份

Calendar.MONTH

月份

Calendar.DATE

日期

Calendar.DAY_OF_MONTH

日期,和上面的字段意义完全相同

Calendar.HOUR

12小时制的小时

Calendar.HOUR_OF_DAY

24小时制的小时

Calendar.MINUTE

分钟

Calendar.SECOND

Calendar.DAY_OF_WEEK

星期几

利用字段类型设置

如果只设定某个字段,例如日期的值,则可以使用如下set方法:

public void set(int field,int value)

把 c1对象代表的日期设置为10号,其它所有的数值会被重新计算

c1.set(Calendar.DATE,10);

把c1对象代表的年份设置为2008年,其他的所有数值会被重新计算

c1.set(Calendar.YEAR,2008);

其他字段属性set的意义以此类推

Add设置

Calendar c1 = Calendar.getInstance();

把c1对象的日期加上10,也就是c1也就表示为10天后的日期,其它所有的数值会被重新计算

c1.add(Calendar.DATE, 10);

把c1对象的日期减去10,也就是c1也就表示为10天前的日期,其它所有的数值会被重新计算

c1.add(Calendar.DATE, -10);

其他字段属性的add的意义以此类推

Calendar类对象信息的获得

Calendar c1 = Calendar.getInstance();
// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1;
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
int day = c1.get(Calendar.DAY_OF_WEEK);

字符串相关 熟悉

String 类

下面是 String 类支持的方法,更多详细,参看 Java String API 文档:

SN(序号)

方法描述

1

char charAt(int index)

返回指定索引处的 char 值。

2

int compareTo(Object o)

把这个字符串和另一个对象比较。

3

int compareTo(String anotherString)

按字典顺序比较两个字符串。

4

int compareToIgnoreCase(String str)

按字典顺序比较两个字符串,不考虑大小写。

5

String concat(String str)

将指定字符串连接到此字符串的结尾。

6

boolean contentEquals(StringBuffer sb)

当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。

7

static String copyValueOf(char[] data)

返回指定数组中表示该字符序列的 String。

8

static String copyValueOf(char[] data, int offset, int count)

返回指定数组中表示该字符序列的 String。

9

boolean endsWith(String suffix)

测试此字符串是否以指定的后缀结束。

10

boolean equals(Object anObject)

将此字符串与指定的对象比较。

11

boolean equalsIgnoreCase(String anotherString)

将此 String 与另一个 String 比较,不考虑大小写。

12

byte[] getBytes()

使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

13

byte[] getBytes(String charsetName)

使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

14

void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

将字符从此字符串复制到目标字符数组。

15

int hashCode()

返回此字符串的哈希码。

16

int indexOf(int ch)

返回指定字符在此字符串中第一次出现处的索引。

17

int indexOf(int ch, int fromIndex)

返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。

18

int indexOf(String str)

返回指定子字符串在此字符串中第一次出现处的索引。

19

int indexOf(String str, int fromIndex)

返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。

20

String intern()

返回字符串对象的规范化表示形式。

21

int lastIndexOf(int ch)

返回指定字符在此字符串中最后一次出现处的索引。

22

int lastIndexOf(int ch, int fromIndex)

返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。

23

int lastIndexOf(String str)

返回指定子字符串在此字符串中最右边出现处的索引。

24

int lastIndexOf(String str, int fromIndex)

返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。

25

int length()

返回此字符串的长度。

26

boolean matches(String regex)

告知此字符串是否匹配给定的正则表达式。

27

boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)

测试两个字符串区域是否相等。

  • ignoreCase -- 如果为 true,则比较字符时忽略大小写。

  • toffset -- 此字符串中子区域的起始偏移量。

  • other -- 字符串参数。

  • ooffset -- 字符串参数中子区域的起始偏移量。

  • len -- 要比较的字符数。

public class Test {

public static void main(String args[]) {

String Str1 = new String("www.runoob.com");

String Str2 = new String("runoob");

String Str3 = new String("RUNOOB");

System.out.print("返回值 :" );

System.out.println(Str1.regionMatches(4, Str2, 0, 5));//true

System.out.print("返回值 :" );

System.out.println(Str1.regionMatches(4, Str3, 0, 5));//false

System.out.print("返回值 :" );

System.out.println(Str1.regionMatches(true, 4, Str3, 0, 5));//true

}

}

28

boolean regionMatches(int toffset, String other, int ooffset, int len)

测试两个字符串区域是否相等。

29

String replace(char oldChar, char newChar)

返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。(注意是一个字符替换

30

String replaceAll(String regex, String replacement)

使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

31

String replaceFirst(String regex, String replacement)

使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。

32

String[] split(String regex)

根据给定正则表达式的匹配拆分此字符串。

33

String[] split(String regex, int limit)

根据匹配给定的正则表达式来拆分此字符串。

34

boolean startsWith(String prefix)

测试此字符串是否以指定的前缀开始。

35

boolean startsWith(String prefix, int toffset)

测试此字符串从指定索引开始的子字符串是否以指定前缀开始。

例如

String Str = new String("www.runoob.com");

System.out.println(Str.startsWith("runoob", 4) );//返回true

表示从指定的位置开始算,是否是对应的前缀runnoob

36

CharSequence subSequence(int beginIndex, int endIndex)

返回一个新的字符序列,它是此序列的一个子序列。从0开始包前不包后

37

String substring(int beginIndex)

返回一个新的字符串,它是此字符串的一个子字符串。

38

String substring(int beginIndex, int endIndex)

返回一个新字符串,它是此字符串的一个子字符串。

39

char[] toCharArray()

将此字符串转换为一个新的字符数组。

40

String toLowerCase()

使用默认语言环境的规则将此 String 中的所有字符都转换为小写。

41

String toLowerCase(Locale locale)

使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。

42

String toString()

返回此对象本身(它已经是一个字符串!)。

43

String toUpperCase()

使用默认语言环境的规则将此 String 中的所有字符都转换为大写。

44

String toUpperCase(Locale locale)

使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。

45

String trim()

返回字符串的副本,去掉最前面和最后面的空白。

46

static String valueOf(primitive data type x)

返回给定data type类型x参数的字符串表示形式。

47

contains(CharSequence chars)

判断是否包含指定的字符系列。

48

isEmpty()

判断字符串是否为空。

substring() 方法

substring() 方法返回字符串的子字符串。

public String substring(int beginIndex)

或

public String substring(int beginIndex, int endIndex)
  • beginIndex -- 起始索引(包括), 索引从 0 开始。

  • endIndex -- 结束索引(不包括)。

  • 从0开始包前不包后

public class RunoobTest {
    public static void main(String args[]) {
        String Str = new String("This is text");
 
        System.out.print("返回值 :" );
        System.out.println(Str.substring(3) );
 
        System.out.print("返回值 :" );
        System.out.println(Str.substring(3, 10) );
    }
}

以上程序执行结果为:

返回值 :s is text
返回值 :s is te

split() 方法

split() 方法根据匹配给定的正则表达式来拆分字符串。

注意: .$|* 等转义字符,必须得加 \\

注意:多个分隔符,可以用 | 作为连字符。

public String[] split(String regex, int limit)
  • regex -- 正则表达式分隔符。

  • limit -- 分割的份数。

public class Test {
    public static void main(String args[]) {
        String str = new String("Welcome-to-Runoob");
 
        System.out.println("- 分隔符返回值 :" );
        for (String retval: str.split("-")){
            System.out.println(retval);
        }
 
        System.out.println("");
        System.out.println("- 分隔符设置分割份数返回值 :" );
        for (String retval: str.split("-", 2)){
            System.out.println(retval);
        }
 
        System.out.println("");
        String str2 = new String("www.runoob.com");
        System.out.println("转义字符返回值 :" );
        for (String retval: str2.split("\\.", 3)){
            System.out.println(retval);
        }
 
        System.out.println("");
        String str3 = new String("acount=? and uu =? or n=?");
        System.out.println("多个分隔符返回值 :" );
        for (String retval: str3.split("and|or")){
            System.out.println(retval);
        }
    }
}

以上程序执行结果为:

- 分隔符返回值 :
Welcome
to
Runoob

- 分隔符设置分割份数返回值 :
Welcome
to-Runoob

转义字符返回值 :
www
runoob
com

多个分隔符返回值 :
acount=? 
 uu =? 
 n=?

Java StringBuffer 和 StringBuilder 类

当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。

public class RunoobTest{
    public static void main(String args[]){
        StringBuilder sb = new StringBuilder(10);
        sb.append("Runoob..");
        System.out.println(sb);  
        sb.append("!");
        System.out.println(sb); 
        sb.insert(8, "Java");
        System.out.println(sb); 
        sb.delete(5,8);
        System.out.println(sb);  
    }
}

以上实例编译运行结果如下:

Runoob..
Runoob..!
Runoob..Java!
RunooJava!

StringBuffer 方法

以下是 StringBuffer 类支持的主要方法:

序号

方法描述

1

public StringBuffer append(String s)

将指定的字符串追加到此字符序列。

2

public StringBuffer reverse()

将此字符序列用其反转形式取代。

3

public delete(int start, int end)

移除此序列的子字符串中的字符。

4

public insert(int offset, int i)

将 int 参数的字符串表示形式插入此序列中。

5

insert(int offset, String str)

将 str 参数的字符串插入此序列中。

6

replace(int start, int end, String str)

使用给定 String 中的字符替换此序列的子字符串中的字符。

注意:这些带下标的都是从0开始包前不包后

StringBuffer 方法

以下列表列出了 StringBuffer 类的其他常用方法:

序号

方法描述

1

int capacity()

返回当前容量。

2

char charAt(int index)

返回此序列中指定索引处的 char 值。

3

void ensureCapacity(int minimumCapacity)

确保容量至少等于指定的最小值。

4

void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

将字符从此序列复制到目标字符数组 dst。

5

int indexOf(String str)

返回第一次出现的指定子字符串在该字符串中的索引。

6

int indexOf(String str, int fromIndex)

从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。

7

int lastIndexOf(String str)

返回最右边出现的指定子字符串在此字符串中的索引。

8

int lastIndexOf(String str, int fromIndex)

返回 String 对象中子字符串最后出现的位置。

9

int length()

返回长度(字符数)。

10

void setCharAt(int index, char ch)

将给定索引处的字符设置为 ch。

11

void setLength(int newLength)

设置字符序列的长度。

12

CharSequence subSequence(int start, int end)

返回一个新的字符序列,该字符序列是此序列的子序列。

13

String substring(int start)

返回一个新的 String,它包含此字符序列当前所包含的字符子序列。

14

String substring(int start, int end)

返回一个新的 String,它包含此序列当前所包含的字符子序列。

15

String toString()

返回此序列中数据的字符串表示形式。

数学计算相关 熟悉

下面的表中列出的是 Number & Math 类常用的一些方法:

序号

方法与描述

1

xxxValue()

将 Number 对象转换为xxx数据类型的值并返回。

2

compareTo()

将number对象与参数比较。

3

equals()

判断number对象是否与参数相等。

4

valueOf()

返回一个 Number 对象指定的内置数据类型

5

toString()

以字符串形式返回值。

6

parseInt()

将字符串解析为int类型。

7

abs()

返回参数的绝对值。

8

ceil()

返回大于等于( >= )给定参数的的最小整数,类型为双精度浮点型。

9

floor()

返回小于等于(<=)给定参数的最大整数 。

10

rint()

返回与参数最接近的整数。返回类型为double。

11

round()

它表示四舍五入,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整,所以,Math.round(11.5) 的结果为12,Math.round(-11.5) 的结果为-11。

12

min()

返回两个参数中的最小值。

13

max()

返回两个参数中的最大值。

14

exp()

返回自然数底数e的参数次方。

15

log()

返回参数的自然数底数的对数值。

16

pow()

返回第一个参数的第二个参数次方。

17

sqrt()

求参数的算术平方根。

18

sin()

求指定double类型参数的正弦值。

19

cos()

求指定double类型参数的余弦值。

20

tan()

求指定double类型参数的正切值。

21

asin()

求指定double类型参数的反正弦值。

22

acos()

求指定double类型参数的反余弦值。

23

atan()

求指定double类型参数的反正切值。

24

atan2()

将笛卡尔坐标转换为极坐标,并返回极坐标的角度值。

25

toDegrees()

将参数转化为角度。

26

toRadians()

将角度转换为弧度。

27

random()

返回一个随机数。

Math 的 floor,round 和 ceil 方法实例比较

ceil()

返回大于等于( >= )给定参数的的最小整数,类型为双精度浮点型。

floor()

返回小于等于(<=)给定参数的最大整数 。

round()

它表示四舍五入,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整,所以,Math.round(11.5) 的结果为12,Math.round(-11.5) 的结果为-11

参数

Math.floor

Math.round(四舍五入)

Math.ceil

1.4

1

1

2

1.5

1

2

2

1.6

1

2

2

-1.4

-2

-1

-1

-1.5

-2

-1

-1

-1.6

-2

-2

-1

Math.floor(1.4)=1.0
Math.round(1.4)=1
Math.ceil(1.4)=2.0
Math.floor(1.5)=1.0
Math.round(1.5)=2
Math.ceil(1.5)=2.0
Math.floor(1.6)=1.0
Math.round(1.6)=2
Math.ceil(1.6)=2.0
Math.floor(-1.4)=-2.0
Math.round(-1.4)=-1
Math.ceil(-1.4)=-1.0
Math.floor(-1.5)=-2.0
Math.round(-1.5)=-1
Math.ceil(-1.5)=-1.0
Math.floor(-1.6)=-2.0
Math.round(-1.6)=-2
Math.ceil(-1.6)=-1.0

多线程

多线程编程 了解

一个线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期。

  • 新建状态:

使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

  • 就绪状态:

当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

  • 运行状态:

如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

  • 阻塞状态:

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

  • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

  • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

  • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

  • 死亡状态:

一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

线程的优先级

每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY ),1 代表最低优先级,10 代表最高优先级。

默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。

创建一个线程的方法

Java 提供了三种创建线程的方法:

  • 通过实现 Runnable 接口;

  • 通过继承 Thread 类本身;

  • 通过 Callable 和 Future 创建线程。

通过实现 Runnable 接口来创建线程

创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。

为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:

public void run()

你可以重写该方法,重要的是理解的 run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。

在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。

Thread 定义了几个构造方法,下面的这个是我们经常使用的:

Thread(Runnable threadOb,String threadName);

这里,threadOb 是一个实现 Runnable 接口的类的实例,并且 threadName 指定新线程的名字。

新线程创建之后,你调用它的 start() 方法它才会运行。

void start();

下面是一个创建线程并开始让它执行的实例:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

编译以上程序运行结果如下:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

通过继承Thread来创建线程

创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。

继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。

该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

编译以上程序运行结果如下:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

通过 Callable 和 Future 创建线程

1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。

2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。

3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。

4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args)  
    {  
        CallableThreadTest ctt = new CallableThreadTest();  
        FutureTask<Integer> ft = new FutureTask<>(ctt);  
        for(int i = 0;i < 100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
            if(i==20)  
            {  
                new Thread(ft,"有返回值的线程").start();  
            }  
        }  
        try  
        {  
            System.out.println("子线程的返回值:"+ft.get());  
        } catch (InterruptedException e)  
        {  
            e.printStackTrace();  
        } catch (ExecutionException e)  
        {  
            e.printStackTrace();  
        }  
  
    }
    @Override  
    public Integer call() throws Exception  
    {  
        int i = 0;  
        for(;i<100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" "+i);  
        }  
        return i;  
    }  
}

创建线程的三种方式的对比

  • 1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

  • 2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

多线程的使用

有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。

通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。

请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!

Thread 方法

下表列出了Thread类的一些重要方法:

序号

方法描述

1

public void start()

使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

2

public void run()

如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

3

public final void setName(String name)

改变线程名称,使之与参数 name 相同。

4

public final void setPriority(int priority)

更改线程的优先级。

5

public final void setDaemon(boolean on)

将该线程标记为守护线程或用户线程。

6

public final void join(long millisec)

等待该线程终止的时间最长为 millis 毫秒。

7

public void interrupt()

中断线程。

8

public final boolean isAlive()

测试线程是否处于活动状态。

上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。

序号

方法描述

1

public static void yield()

暂停当前正在执行的线程对象,并执行其他线程。

2

public static void sleep(long millisec)

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

3

public static boolean holdsLock(Object x)

当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。

4

public static Thread currentThread()

返回对当前正在执行的线程对象的引用。

5

public static void dumpStack()

将当前线程的堆栈跟踪打印至标准错误流。

JVM

JVM 内存模型和结构 了解

总体来说,方法区和堆是所有线程共享的内存区域;而虚拟机栈、本地方法栈和程序计数器的运行是线程私有的内存区域,运行时数据区域就是我们常说的JVM的内存

  • 类加载子系统:根据给定的全限定名类名(如:java.lang.Object)来装载class文件到运行时数据区中的方法区中

  • Java堆是Java虚拟机所管理的内存中最大的一块,也是垃圾回收的主要区域。堆就是给对象分配内存,用来存放对象实例

  • 方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(注意这里没有局部变量,局部变量是存在栈中的)

  • 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器,存储执行引擎下一条执行指令的地址。

  • 虚拟机栈描述的是Java方法执行的内存模型:每个java方法被执行的时候都会同时在虚拟机栈中创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、返回方法地址等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程,Java虚拟机栈也是线程私有的,它的生命周期与线程相同。

  • 本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务

  • 执行引擎(解释器):根据程序计数器中存储的指令地址执行classes中的指令

  • 本地接口:与本地方法库交互,是其它编程语言交互的接口。

JVM各个组成部分的作用

首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader) 再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能(调用本地库接口因为不同的操作系统的底层是不同的语言写的,然后虚拟机要把这个class字节码转为对应操作系统的机器码就需要调用本地库接口来调用本地库方法,里面有其他语言的交互)

练习题

题目1

题目2

题目3

题目4

题目5

题目6

题目7

题目8

题目9

题目10

题目11

题目12

题目13

题目14

题目15

题目16

题目17

题目18

题目19

题目20

题目21

题目22

题目23

回炉重造地址:https://www.runoob.com/java/java-tutorial.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

18. 循环语句while,for语句的详解

python 中的循环语句只有 for 和 while两种&#xff0c;没有do…while循环&#xff0c;这与c/c是不同的。 1. while循环 (1) 语法格式 while <condition>&#xff1a;...# demo, 使用while循环累加1-100的和。 sum 0 counter 1 while counter < 100:sum counterco…

Java 23种设计模式(4.创建者模式-建造者模式)

代码分析 结构图 代码 public class Product {//产品类,多个部件构成List <String> parts new ArrayList<>();public void Add(String part){parts.add(part);}public void show(){System.out.println("creat parts");for(String part:parts){System…

第十届蓝桥杯省赛 C++ B/C组 - 等差数列

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;蓝桥杯题解集合 &#x1f4dd;原题地址&#xff1a;等差数列 &#x1f4e3;专栏定位&#xff1a;为想参加蓝桥杯的小伙伴整理常考算法题解&#xff0c;祝大家…

STL分析(九 适配器)

容器适配器&#xff1a;stack&#xff0c;queue stack和queue内含一个deque 函数适配器 binder2nd绑定第二参数 调用的过程中&#xff0c;算法count_if函数读取了迭代器头尾指针后&#xff0c;读取第三个参数为functor object即仿函数。因此在其参数为bind2nd(less< int&g…

LeetCode220123_140、117. 填充每个节点的下一个右侧节点指针 II

给定一个二叉树struct Node {int val;Node *left;Node *right;Node *next;}填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL。初始状态下&#xff0c;所有 next 指针都被设置为 NULL。进阶…

双指针思想,c语言

问题导入 对一个给定的自然数M&#xff0c;求出所有的连续的自然数段&#xff0c;这些连续的自然数段中的全部数之和为M。 例如&#xff1a;1998 1999 2000 2001 2002 10000&#xff0c;所以从1998到2002的一个自然数段为M 10000的一个解。 输入格式 第一行&#xff0…

JQuery总结(三)

jQuery 事件 on可以同时绑定多个事件&#xff0c;并且动态添加的元素也会自动添加事件 自动触发事件&#xff1a; 案例1&#xff1a; <style>div{width: 100px;height: 200px;background-color: violet;transition: all .5s;}.current{width: 200px;height: 100px;ba…

ARP渗透与攻防(三)之流量分析

ARP攻击-流量分析 ARP渗透与攻防(一)之ARP原理 ARP渗透与攻防(二)之断网攻击 系列文章 1.环境准备 1.kali作为攻击机 2.win10作为靶机 IP地址&#xff1a;192.168.110.11 3.网关 IP地址&#xff1a;192.168.110.1 2.kali数据包转发 出于安全考虑&#xff0c;Linux系统默…

使用Py6S计算瑞利反射率教程

1、前言那么&#xff0c;首先&#xff0c;什么是瑞利反射率&#xff1f; 好吧&#xff0c;这是由大气中的瑞利散射引起的反射率&#xff08;在大气层顶部测量&#xff09;。 这是大气中气体分子对光的波长依赖性散射——这是光穿过大气时不可避免的结果。所以&#xff0c;关于如…

【2022年度总结与2023展望】---22年故事不长,且听我来讲

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f4e3;系列专栏&#xff1a;故事 文章目录前言一、高考前及高考后的暑假二、大一上的生活2.1 感受校园美景2.2 进入ACM实验室2.3 比赛和比赛经历三、那些帮助过我的人…

AlmaLinux 9 安装Oracle GraalVM Enterprise Edition 22.3.x

今天我们尝试一下在AlmaLinux 9 安装Oracle GraalVM Enterprise Edition 22.3.x。 GraalVM Enterprise 22是包含新功能的最新版本&#xff0c;但不是Long-Term-Support (LTS) 版本。 注意&#xff1a;下载Oracle GraalVM Enterprise Edition需要有Oracle账户&#xff0c;如果没…

六、pyhon操作mysql篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 1. 下载pymysql 2. 新建数据库 3. mysql服务器版本查询 4. 执行非查询性质的SQL 5. 执行查询性质的sql ​​​​​​​6. 执行新增sql 1. 下载pymysql 右下角点击版本 选择解释器设…

基于Markdown文件的个人wiki

节后第一更&#xff0c;老苏祝您兔年大吉&#xff0c;幸福安康&#xff0c;事事顺心&#xff01; 什么是 wikmd &#xff1f; wikmd 是一个基于文件的 wiki&#xff0c;旨在简化。这些文档完全用 Markdown 编写&#xff0c;使用 pandoc 将 Markdown 文件转换为 html5。 &#…

WPF__Viewport3D 学习记录

1、相机的摆放位置和姿态 Position 是指定照相机的位置&#xff0c;注意Z轴的坐标&#xff0c;如果Z轴值大于模型的Z轴值&#xff0c;那么镜头就在物体前面&#xff0c;反之在物体后面。因此&#xff0c;你可以设置 LookDirection 来调整相机的方向&#xff0c;Position是相机的…

NodeJS 之模块化

NodeJS 之模块化参考描述模块化优点分类加载模块作用域优点自定义模块modulemodule.exportsexports 与 module.exports示例示例一示例二示例三建议CommonJS规范CommonJS参考 项目参考搜索引擎Bing哔哩哔哩黑马程序员 描述 项目描述操作系统Windows 10 专业版NodeJS18.13.0 模…

MU-MIMO是什么

欢迎来到东用知识小课堂&#xff01;1.什么是MIMOMIMO&#xff1a;Multiple-Intput Multiple-Output,即多入多出系统&#xff0c;这里的入和出是相对于发射天线和接受天线构成的天线系统来讲。通常的通信系统是单发单收&#xff0c;也就是SISO&#xff1a;Single-Input Single-…

【Bp2Lua】蓝图定义 Struct 和 Enum

【Bp2Lua】蓝图定义 Struct 和 Enum 背景 Enum Struct 结论 enum 可以保持不动&#xff0c;使用枚举值注释&#xff1b;如果C特别需要访问 enum&#xff0c;可以 C 化struct 必须 C 化 坑 首先&#xff0c;从字段访问都有字段名的坑&#xff0c;名字可以有空格&#xff0c…

maven-3-java调用python程序

【Java】使用Java调用Python的四种方法 fastjson的使用——JSON字符串、JSON对象、Java对象的互转 使用idea给Java程序打jar包&#xff08;超简单 超详细&#xff09; 1 环境准备 (1)新建Maven类型的项目&#xff0c;D:\processPython。 右键src/main/java&#xff0c;创建ja…

基于深度学习的文本分类6大算法-原理、结构、论文、源码打包分享

导读&#xff1a;文本分类是NLP领域一项基础工作&#xff0c;在工业界拥有大量且丰富的应用场景。传统的文本分类需要依赖很多词法、句法相关的human-extracted feature&#xff0c;自2012年深度学习技术快速发展之后&#xff0c;尤其是循环神经网络RNN、卷积神经网络CNN在NLP领…

【Leetcode面试常见题目题解】8. 合并两个有序链表

前言 本文是LC第21题&#xff1a;合并两个有序链表 题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 提示&#xff1a; 两个链表的节点数目范围是 [0, 50] -100 < Node.val < 100 l1 和 l2 均按 非递减顺…