类与对象基础
变量定义
来源:牛客网
- 实例变量: 定义在类中的变量是类的成员变量,可以不进行初始化, java 会自动进行初始化。(如果是引用类默认初始化为 null, 如果是基本类型,默认初始化为 0 )
- 局部变量 :定义在方法中的变量,必须进行初始化,否则不通过编译。
- 类变量 :(也叫作静态变量)是类中独立于方法之外的变量,用 static 修饰。
- final 修饰的变量: 也称为常量。
成员变量的定义
用transient
修饰的变量叫做临时变量。临时变量在对象序列化时不被作为持久状态的一部分存储。
用volatile
修饰的变量称为共享变量。在多线程的程序中,共享变量可以被异步修改。
成员方法的定义
用final
修饰的方法称为最终方法,最终方法不能被覆盖。方法的覆盖与继承有关。
用abstract
修饰的方法称为抽象方法。
用synchronized
修饰的方法称为同步方法。同步方法主要用于开发多线程程序。
用native
修饰的方法称为本地方法,本地方法用来调用其他语言(如C语言)编写的函数。
方法重载
Java语言提供了方法重载的机制,允许在一个类中定义多个同名的方法,这称为方法重载(method overloading)。实现方法重载,要求同名的方法要么参数个数不同,要么参数类型不同,仅返回值不同不能作为区分重载的方法。方法重载就是在类中允许定义签名不同的方法。
在类中定义了重载方法后,对重载方法的调用与一般方法的调用相同。
在调用重载的方法时还可能发生自动类型转换。假设没有定义一个带有一个int参数的show方法,od.show(10);
将调用带double参数的show方法。
通过方法的重载可以实现编译时多态(静态多态),编译器根据参数的不同调用相应的方法,具体调用哪个方法是由编译器在编译阶段静态决定的。我们经常使用的输出语句中的println就是重载方法的典型例子,它可以接收各种类型的参数。
构造
如果在构造方法中调用另一个构造方法,则该语句必须是第一条语句。
静态变量
对于静态变量,Java运行的时候系统在类装载的时候为这个类的每个静态变量分配一块内存,以后再生成该类的对象的时候,这些对象将共享同名的静态变量,每个对象对静态变量的改变都会影响到其他对象。
通常,static
和final
一起使用来定义类常量。
对象的初始化和清除
尽管Java提供了垃圾回收器,但是不能保证不被使用的对象及时被回收。如果希望系统运行垃圾回收器,可以直接调用System
类的gc
方法(System.gc();
)。另一种调用垃圾回收器的方法是通过Runtime
类的gc
实例方法(Runtime rt = Runtime.getRuntime();rt.gc();
)。
注意:启动垃圾回收器并不意味着马上能回收无用的对象。垃圾回收器需要一定的时间,且受各种因素,如内存堆的大小、处理器的速度等的影响,因此垃圾回收器的真正执行实在启动垃圾回收器后的某个时刻才能执行。
数组
数组复制
public class ArrayCopy {
public static void main(String[] args) {
ArrayCopyTest arrayCopyTest = new ArrayCopyTest();
arrayCopyTest.TestCopy();
}
}
class ArrayCopyTest {
void TestCopy() {
int[] one = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int[] two = new int[one.length];
System.arraycopy(one, 0, two, 0, one.length);
StringBuilder sb = new StringBuilder();
for (int i : two) {
sb.append(i).append(" ");
}
System.out.println(sb.toString());
}
}
其中,System.arraycopy(one, 0, two, 0, one.length);
中System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
, 其中src为原数组;srcPos为源数组的起始下标;destPos为目的数组下标;length为复制的数组元素的个数。
使用arraycopy
方法可以将原数组的一部分复制到目标数组中。注意,如果目标数组不足以容纳源数组元素,会抛出异常。
可变参数的方法
从Java5开始,允许定义方法(包括构造方法)带可变数量的参数。这种方法称为可变参数(variable argument)方法。具体做法是在方法参数列表的最后一个参数的类型名之后、参数名之前使用省略号。
public class ArrayCopy {
public static void main(String[] args) {
Test test = new Test();
test.avg("Java", "Kotlin", "Scala");
}
}
class Test {
public void avg(String ... strings) {
for (String s:strings) {
System.out.println(s);
}
}
}
字符串及应用
字符串的解析
String类提供了一个split方法,实现将一个字符串分解成子字符串或者令牌(token)。该方法使用正则表达式制定分隔符。
方法 | 说明 |
---|---|
public String[] split(String regex, int n) | 参数regex表示正则表达式,n表示模式应用的次数。如果n的值为0,则模式将应用尽可能多的次数,末尾的空字符串被丢弃。如果n的值大于0,则模式至多被应用n-1次,结果数组的长度不大于n,数组的最后一项将包含除最后一个匹配的分隔符外的所有输入内容。如果n的值小于0,则模式将应用尽可能多的次数。 |
public String[] split(String regex) | 与上述方法n为0的情况相同。 |
public boolean matches(String regex) | 返回字符串是否与给定的正则表达式匹配。 |
字符串的比较
Java语言中“==”比较引用类型的数据(对象)时,比较的是引用(地址)是否相等。只有两个引用指向同一个对象的时候,结果才为true。
String对象的不变性
在Java程序中,一旦创建了一个String对象,就不能对其内容进行改变Java的String对象是不可变的字符串。
有些方法看起来是修改了字符串,但是字符串修改后产生了另一个字符串,这些方法对字符串没有任何影响,原字符串永远不会改变。
public class StringTest {
public static void main(String[] args) {
Test test = new Test();
test.testString();
}
}
class Test {
void testString() {
String string = "Hello World";
string.replace("o", "A");
System.out.println(string);
string = string.substring(0,6).concat("Java");
string.toUpperCase();
System.out.println(string);
}
}
命令行参数
下面程序从命令行为程序传递三个参数,在main()中通过arg[0]、arg[1]、arg[2]输出这三个参数的值。
public class Test {
public static void main(String[] args) {
System.out.println(args[0] + " " + args[1] + " " + args[2]);
}
}
StringBuilder
方法 | 说明 |
---|---|
public StringBuilder() | 创建一个没有字符的字符串缓冲区,初始容量为16个字符。此时length()方法的值为0,而capacity方法的值为16。 |
public StringBuilder(int capacity) | 创建一个没有字符的字符串缓冲区,capacity为指定的初始容量。 |
public StringBuilder(String str) | 利用一个已存在的字符串对象str创建一个字符串缓冲区,另外再分配16个字符的缓冲区。 |
String
:适用于少量的字符串操作的情况StringBuilder
:适用于单线程下在字符缓冲区进行大量操作的情况StringBuffer
:适用多线程下在字符缓冲区进行大量操作的情况
正则表达式
- 详情请看 -> 正则表达式
模式的指定
最简单的模式可以包含一个字符。要指定多个字符或者字符范围,需要使用方括号将字符括起来。
正则表达式 | 说明 |
---|---|
[abc] | 匹配a、b、c |
[^abc] | 匹配除了a、b、c以外的所有字符 |
[a-zA-Z] | 匹配a~z和A~Z的字符 |
[a-d[m-p]] | a~d或者m~p(并) |
[a-z&&[def]] | d、e或者f(交) |
[a-z&&[^bc]] | 除了b、c以外a~z:[ad-z](差) |
[a-z&&[^m-p]] | a~z中除了m~p以外的字符:[a-lq-z](差) |
在模式串中还可以使用一些预定义的字符,称为元字符。
元字符 | 说明 |
---|---|
. | 匹配任何单个字符 |
\d | 一个数字:[0-9] |
\D | 一位非数字:[^0-9] |
\s | 空格字符:[\t\n\x0B\f\r] |
\S | 非空格字符:[^\s] |
\w | 一个单词字符:[a-zA-Z_0-9] |
\W | 一个非单词字符:[^\w] |
Pattern类
方法 | 说明 |
---|---|
public static Pattern compile(String regex) | 将给定的正则表达式编译成Pattern类的一个实例,如果表达式语法错误,将抛出PatternSyntaxException运行时异常。 |
public static Pattern compile(String regex, int flags) | flags参数用来指定匹配如何进行,它使用Pattern类的一个常量。 |
public String pattern() | 返回该模式对象的正则表达式字符串。 |
public Matcher matcher(CharSequence input) | 创建按照模式与给定的输入字符序列匹配的Matcher对象。 |
public static boolean matches(String regex, CharSequence input) | 对规定的正则表达式 编译并与输入序列匹配,如果成功则返回true。当不需要重复使用匹配器的时候可以使用这个方法。 |
public String[] split(CharSequence input) | 使用该模式对象对输入字符序列进行拆分。 |
public String[] split(CharSequence input, int limit) | limit参数用于控制模式使用的次数,它将影响结果数组的长度。 |
public int flags() | 返回该模式的匹配标志。 |
Matcher类
Matcher类的实例用来根据给定的模式匹配字符序列。通过调用模式对象的matcher方法来得到一个Matcher类的对象。
执行匹配的方法
方法 | 说明 |
---|---|
public boolean matches() | 尝试将整个输入序列与该模式进行匹配。如果返回true,就匹配成功,匹配成功之后就可以使用start方法、end方法和group方法获得更多的信息。 |
public boolean lookingAt() | 尝试从开始处的输入序列与该模式进行匹配。与matches方法不同的是它不需要匹配整个输入序列。 |
public boolean find() | 尝试查找输入序列中与该模式匹配的下一个序列的开头匹配,或者,如果上一次find方法是成功的,并且匹配器没有重置,则本次匹配从上次匹配中还没有进行匹配的第一个字符开始。 |
public boolean find(int start) | 重置该匹配器,然后尝试从制定索引位置开始查找与该模式匹配的下一个子序列。 |
返回匹配信息的方法
方法 | 说明 |
---|---|
public int start() | 返回上次成功匹配的开始索引值。 |
public int end() | 返回匹配的序列中最后一个字符的索引值加1的值。 |
public String group() | 返回匹配成功的子序列,即由start和end定义的子字符串。 |
public int groupCount() | 返回该匹配模式中的捕获数组。组号范围从0开始,到这个组数减1的值。 |
public String group(int group) | 返回上次匹配中与给定组匹配的输入子序列。第0组表示整个匹配模式,所以group(0)与group()等价。 |
public int start(int group) | 返回上次匹配中给定组的开始索引值。 |
public int end(int group) | 返回与给定组匹配的序列中最后一个字符的索引值加1。 |
改变匹配器状态的方法
方法 | 说明 |
---|---|
public Matcher reset() | 重置适配器,该方法将丢弃该匹配器的所有状态信息,并将其追加位置重置为0,该方法返回的Matcher对象就是调用该方法的Matcher对象。 |
public Matcher reset(CharSequence input) | 将匹配器重置为使用新的输入序列。 |
public Matcher usePattern(Pattern pattern) | 将该匹配器使用的模式重新设置为传递进来的模式pattern。 |
量词和捕获组
贪婪量词 | 勉强量词 | 具有量词 | 模式X出现的次数 |
---|---|---|---|
X? | X?? | X? + | X出现0次或者1次。 |
X* | X*? | X*+ | X出现0次或者多次。 |
X+ | X+? | X++ | X出现1次或者多次。 |
X{n} | X{n}? | X{n}+ | X恰好出现n次。 |
X{n, } | X{n, }? | X{n, }+ | X至少出现n次。 |
X{n, m} | X{n, m}? | X{n, m}+ | X至少出现n次,但不超过m次。 |
捕获
上述操作也可用于一组字符上,这称为捕获组。一个捕获组是将一组字符作为一个单元处理。例如,(Kotlin)
是一个捕获组,这里的Kotlin是一个单元,ScalaScala
属于(Scala)*
正则表达式。在输入串中与捕获组匹配的部分将被保存,然后通过向后引用调用。
Java语言提供了对正则表达式中捕获组标识的计数,它是通过正则表达式中左括号的个数计数的。例如,在正则表达式((A)(B(C)))
中由四个捕获组:
((A)(B(C)))
(A)
(B(C))
(C)
正则表达式 | 输入串 | 结果 |
---|---|---|
([a-z][a-z])\1 | abab | 找到文本“abab”,开始索引为0,结束索引为4。 |
([a-z][a-z])\1 | abcd | 没有找到匹配。 |
([a-z][a-z]) | abcd | 找到文本“ab”,开始索引为0,结束索引为2。找到文本“cd”,开始索引为2,结束索引为4。 |
类的继承
方法的覆盖
在子类中可以定义与超类中名字、参数列表、返回值类型都相同的方法,这时子类的方法就叫做覆盖(overriding)或重写了超类的方法。
方法覆盖的注意事项
- 对访问修饰符非private的实例方法才可以覆盖,private方法不能覆盖。如果在子类中定义了一个方法在超类中是private的,则这两个方法完全无关。
- 与实例方法一样,static方法也可以被继承,但static方法不能被覆盖。如果超类中的static方法在子类中重新定义,那么超类中的方法被隐藏。超类中被隐藏的static方法仍然可以使用
SuperClassName.staticMethodName()
形式调用。
已知,方法重载实在一个类中定义多个名称相同但是参数不同的方法。而方法的覆盖实在子类中为潮流的同名方法提供一个不同的实现。要在子类中定义一个覆盖的方法,方法的参数和返回值类型必须和超类中的方法相同。
子类的构造方法
如果在子类的构造方法中若没有使用super
调用超类的构造方法,则编译器将在子类的构造方法的第一句自动加上super()
,即调用超类无参数的构造方法。
另外,在子类的构造方法中也可以使用this
调用本类的构造方法。
final
对于类的成员变量一般使用static和final组合定义类常量。这种常量称为编译时常量,编译器可以将该变量值代入任何可能用到它的表达式中,可以减轻运行时的负担。
- 使用final修饰的类为最终类,不能被继承。
finalize方法
在Java程序中每个对象都有一个finalize方法。在对象被销毁之前,垃圾回收器允许对象调用该方法进行清理工作,这个过程称为对象终结(finalization)。
在程序中每个对象的finalize
方法仅被调用一次。利用这一点,可以在finalize
方法中清除在对象外被分配的资源。典型的例子是,对象可能打开一个文件,该文件可能仍处于打开状态。在finalize
方法中,就可以检查如果文件没有被关闭,就将该文件关闭。
@Override
protected void finalize() throws Throwable {
super.finalize();
// TODO
}
数据类型
基本数据类型和引用数据类型
- 数据类型
- 基本数据类型
- 数值型
- 整数型:byte、short、int、long
- 浮点型:float、double
- 字符型:char
- 布尔型:bool
- 数值型
- 引用数据类型
- 类【Class】
- 接口【Interface】
- 数组【Array】
- 基本数据类型
Java的数据类型分基本数据类型(原始数据类型)和引用数据类型两种:
- 基本八大类,图中可以很清楚的看到;这种类型的数据变量在声明之后Java就会立刻分配给他内存空间。如:
short a;
Java会在可使用的内存空间寻找一个占两个字节的块给a变量; - 引用数据类型就三种(类、接口、数组),类似C/C++的指针,它以特殊的方式指向对象实体(具体的值),这类变量在声明的时候不会分配内存,只是存储了一个内存地址。
摘录自:Java中的数据类型有哪些?
BigInteger和BigDecimal类
如果在计算中需要非常答的整数或者非常高精度的浮点数,可以使用java.math包中定义的BigInteger
和BigDecimal
类。这两个类都扩展了Number类并实现了Comparable
接口,它们的实例都是不可变的。BigInteger的实例可以表示任何大小的整数。可以使用new BigInteger(String)
和new BigDecimal(String)
创建BigInteger
和BigDecimal
实例,然后使用add()
,subtract()
,multiply()
, divide()
,remainder()
等方法执行算术运算,还可以使用compareTo()
比较它们的大小。
中间缓存机制
package algorithms.com.guan.javajicu;
public class Inc {
public static void main(String[] args) {
Inc inc = new Inc();
int i = 0;
inc.fermin(i);
i= i ++;
System.out.println(i);
}
void fermin(int i){
i++;
}
}
正确答案是:0。
解析
- 原地址——牛客网
- Java使用了中间缓存变量机制:
- i=i++;等同于:
- temp=i; (等号右边的i)
- i=i+1; (等号右边的i)
- i=temp; (等号左边的i)
- 而i=++i;则等同于:
- i=i+1;
- temp=i;
- i=temp;
- 但是那些说将i++表达式的结果赋给i的答案,本人表示不理解。
堆栈
- 用new创建的对象在堆区
- 函数中的临时变量在栈去
- java中的字符串在字符串常量区
异常
其他合集
final,finally,finalized的区别
- final 是修饰符,可以用于修饰变量、方法和类。修饰变量时,代表变量不可以修改,也就是常量了,常量需要在定义时赋值或通过构造函数赋值,两者只能选其一;修饰方法时,代表方法只能调用,不能被
override
;修饰类时,代表类不能够派生出子类,所以一个类不能既是final
又是abstract
; - finally 是异常处理机制中的 try 的从句,用于处理必要的清理工作,那怕执行的
catch
中有return
语句finally
也会在return
之前执行; - finalized 是
Object
中定义的一个方法,子类一般都重写该方法,用于在该对象被GC收走前做必要的清理工作,该方法一般供GC调用,但重载finalized
时,GC只会调用最初始版本的finalized
,显式地调用初始版本的finalized
方法具有很大的不确定性。 - 转自:final finally finalized的区别?