记录学习JAVA过程中易意忘的小知识点。
字符类型
1 | char word = 'd'; |
变量
类体中所定义的变量为成员变量。类的成员变量分为静态变量和实例变量。类的方法中定义的为局部变量。
成员变量在设定时需要设置初始值,局部变量在使用时必须进行赋值操作或者被初始化。
静态变量
被声明为static的变量、常量和方法被称为静态成员。静态成员属于类所有,可以在本类或者其他类使用类名和”.”运算符调用静态变量。静态成员同样遵循public、private和protected修饰符的约束。
静态方法中不能使用this关键字。方法内的局部变量不能声明为静态变量。
1 | public class example{ |
栈堆
当运行int x = 3
时,会在栈内存寻找一块区域存放3.
栈内存:数据使用完毕,会自动释放
当这段代码被执行时,首先执行static块中的程序。
当运行int[] x = new int[3]
,栈内存存放一块区域存放数组x的首地址。而数组的元素存放在堆中。此时执行x = null
,则x与堆中的元素没有关系。此时数组在堆内存并没有消失,而是会有java不定时执行垃圾回收机制。
堆内存用来封装数据,当被初始化时,均使用默认值。int型数组的默认值为0,double数组为0.0,float数组为0.0f。
1 | int[] x = new int[3]; |
1 | public class AccessProperty{ |
运算符优先级
增量和减量运算>算术运算>比较运算>逻辑运算>赋值运算
逻辑运算符
&& 短路运算(当第一个表达式为false,则不判定第二个表达式)
&非短路运算(第一个和第二个都会进行判断)
位运算符
左移(<<) 左移空的补0;
右移(>>)右移部位和原始最高为一致;
无符号右移(>>>)右移最高为填0;
foreach
1 | for(元素变量x:遍历对象 obj){ |
字符串
java中将字符串作为对象来管理,因此可以像创建其他类对象一样来创建字符串对象。创建对象要使用类的构造方法。
创建
String(char a[])
1 | char a[] = {'g','o','o','d'}; |
String(char a[], int offset, int length)
1 | char a[] = {'s','t','u','d','e','n','t'}; |
查找
indexOf(String s)
1 | String str = 'We are students'; |
lastIndexOf(String str)
返回字符串最后一次出现的索引位置。如果没有检索到字符串str,该方法返回-1
PS:lastIndexOf()方法中的参数是空字符串,则返回结果与调用该字符串length()方法的返回结果相同。
str.CharAt(int index)
将索引处的字符返回。
获取子字符串
substring()
str.substring(int beginIndex) 返回从索引位置开始截取直到该字符串结尾的字串。
str.substring(int beginIndex, int endIndex)返回从字符串某一索引位置开始截取至某一索引位置结束的字串。
替换
replace(char oldChar, char newChar)
返回替换后的字符串
验证
startsWith(String prefix)
判断当前字符串对象的前缀是否是参数
endsWith(String suffix)
判断当前字符串对象是否以给定的子字符串结束
equals(String otherstr)
比较两个字符串的内容,区分大小写。
对字符串对象进行比较不能简单地使用”==“,比较运算符比较的是两个字符串的地址是否相同。
equalsIgnoreCase()
比较两个字符串的内容,不区分大小写。
compareTo()
按字典顺序比较两个字符串,比较基于字符串中各个字符的Unicode值,如果此String对象位于参数字符串之前,则返回一个负整数;如果在其之后,则返回一个正整数;如果这两个字符串相等,则结果为0。
大小写转换
toLowerCase() 转换成大写
toUpperCase() 转换成小写
分割
split(String sign)
sign为分隔符,多个分隔符之间用|来连接。eg: “,|=” 表示分隔符分别为“,”和“=”
可以使用正则表达式。
split(String sign, int limit)
limit: 限制的分割份数。
PS: | , + , * , ^ , $ , / , | , [ , ] , ( , ) , - , . , \
。例如用|竖线去分割某字符,因|本身是正则表达式中的一部分,所以需要\去转义,因转义使用\,而这\正好也是正则表达式的字符,所以还得用一个\,所以需要两个\。
字符串生成器
StringBuilder对象初始容量为16个字符,可以自行指定初始长度。最后输出StringBuilder的字符串结果,可以使用toString()方法。
append(content)
用于向字符串生成器中追加内容。可以接受任何类型的数据,如int、boolean、char、String、double
insert(int offset,arg)
offset:字符串生成器的位置。 arg:新插入的字符串
delete(int start, int end)
删除从start下标到end下标位置处的字符串。
1 | StringBuilder bf = new StringBuilder("hello"); |
数组
数组的初始化
1 | int arr[] = new int[]{1,2,3,4,5}; //第一种初始化方式 |
数组排序
选择排序法
依次找到数组的最小值
1 | class ArrayTest2{ |
冒泡排序
相邻的两个元素进行比较,如果符合条件换位。
相当于每次找到数组的最大值放在后边
1 | class ArrayTest2{ |
PS:上述排序效率比较低,其在堆内存中排序。如果将排序过程需要置换下标的数据放入栈内存,最后使用堆内存统一排序。则可以提高不少的效率。
置换方法
1 | swap(int[] arr,int a,int b){ //传入一个数组和需要排序的下标 |
PS:将数组传入函数,相当于在栈中存在一个临时数组指向堆中的数组。这样函数操作的数组和实际参数的数组保持一致。
实际开发
1 | import java.util.*; |
数组的查找
折半查找
1 | public static int halfSearch(int[] arr,int key){ |
第二种方式
1 | public static int halfSearch_2(int[] arr,int key){ |
二维数组
初始化
1 | int[][] arr = new int[3][4]; |
1 | int[][] arr = new int[3][]; |
二维数组的遍历
1 | public class Tautog{ |
填充
fill(int[] a, int value)
该方法可将指定的int值分配给int型数组的每个元素。
fill(int []a, int fromIndex, int toIndex, int value)
将int值分配给从索引fromIndex(包括)到toIndex(不包括)范围内的每个元素
排序
Arrays.sort(object);
object是进行排序的数组名称。升序排列
复制
copyOf(arr, int newlength)
arr:要进行复制的数组。
newlength: int型常量,指复制后的新数组的长度。如果新数组的长度大于数组arr的长度,则用0填充(char型数组用null填充);复制后的数组长度小于数组arr的长度,则会从数组arr的的第一个元素开始截取至满意新数组长度为止。
1 | int newarr[] = Arrays.copyOf(arr,5) |
copyOfRange(arr, int formIndex, int toIndex)
复制给从索引fromIndex(包括)到toIndex(不包括)范围内的每个元素
查询
binarySearch(Object[].Object key)
使用二分法搜索法来搜索指定数组。使用前必须将数组排序。如果检索到指定数据,则返回排序后数组的下标。如果未检索到数据,则返回检索数据在数组中排列的位置+1取反。
详细源码:https://blog.csdn.net/qq_40178464/article/details/79942814
binarySearch(Object[], int fromIndex, int toIndex, Object key)
在指定的范围内检查某一元素。指定范围应小于数组长度。
进制转换
十进制转二进制
1 | public static void toBin(int num){ |
十进制转十六进制
1 | public static void toHex(int num){ //计算的方式 |
1 | public static void toHex(int num){ //数组的方式 |
综合进制转换
1 | public static void main(String[] args){ |
类与对象
面向对象的三个特征:封装、继承、多态
变量
成员变量
成员变量在堆内存中,因为对象的存在,才在内存中存在。
局部变量在栈内存中。
对象的比较
1 | public class Compare{ |
类修饰符
如果一个类使用protected修饰符,那么只有本包内的该类的子类或者其他类可以访问此类中的成员变量和方法。默认的修饰符为protected。
在类中没有定义任何构造方法时,编译器才会在该类中自动创建一个不带参数的构造方法。
private Tool(){}:当Tool类的构造函数人为定义私有化时,该类不能创建对象(见单例设计模式)。一般用于工具类,其类里边对外提供的方法均为静态方法。 默认构造函数的修饰符随着类修饰符的变化而变化。
匿名对象
1 | new Car().num = 5; //匿名对象 |
图一:
匿名对象使用方式:当对象的方法只调用一次时,可以用匿名对象来完成;可以将匿名对象作为实际参数进行传递。
1 | //Car q = new Car(); |
构造代码块
1 | class Person{ |
this在构造函数之间的调用
1 | class Person{ |
Static关键字
当所有的对象某一个属性值都是一样的时候,则可以使用static来修饰类中的成员变量。这样所有对象的这个属性公用一个空间,静态的成员变量也称之为类变量。
调用方式:对象.属性 或者 类名.属性
存放位置:静态成员变量随着类的加载而存在与方法区(共享区),实例变量随着对象的建立而存在堆内存中。
生命周期:静态成员变量周期最长。
注意事项:
1.静态方法只能访问静态成员和静态方法;非静态方法既可以访问静态也可以访问非静态。
2.静态方法中不可以定义this,super关键字,因为静态优先于对象存在。
静态特点:
1.静态成员变量随着类的加载而加载,随着类的消失而消失。而普通的成员变量随着对象的存在而存在;
2.对象的共享数据进行单独空间的存储,节省空间。
3.可以被所有对象所共享,可以直接被类名调用。
静态的使用
静态成员变量
当对象中出现共享数据时,该数据被静态所修饰。
对象中的特有数据要定义成静态存在于堆内存中。
静态函数
当函数内部没有访问到非静态数据,那么该函数可以定义为静态的。
主函数
主函数是一个特殊的函数,可以被jvm调用,作为程序的入口。
public:代表着该函数的访问权限是最大的。
static:代表主函数随着类的加载就已经存在了。
void:主函数没有具体的返回值。
main:不是关键字,是一个特殊的单词,可以被jvm识别。
String[] args:字符串类型的数组。只有args可以变。
jvm在调用主函数时,传入的是new String[0];
静态代码块
1 | class StaticCode |
上述例子输出结果为 b c a over。静态代码块随着类的加载而执行,只执行一次,并优先于主函数,用于给类进行初始化。PS
PS:StaticCode s =null
此时类没有被加载。
对象的初始化过程
1 | class Person{ |
Person p = new Person()
的执行顺序:
1 | main函数进入栈中; |
p.setName("lisi")
的执行顺序:
1 | setName方法进入栈内存 |
设计模式
单例设计模式
方法一 饿汉式
可以保证系统中 ,应用该模式的类只有一个实例。
方式:1.将构造函数私有化;2.在类中创建一个本类对象;3.提供一个方法可以获取到该对象。
1 | class Single{ |
方法二 延时加载(懒汉式)
1 | class Single{ |
优点:当类SingleDemo被加载时,静态变量的s未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化s变量,并分配内存,因此在某些特定条件下会节约内存。
缺点:在多线程环境中,这种实现方法是错误的,根本不能保证单例的状态。
改进:public static Single getInstance()
=>public static synchronized Single getInstance()
线程锁的存在使程序效率低下。
改改进:
1 | if(s == null){ |
开发一般用饿汉式
继承
继承提高了代码的复用性;让类与类之间产生了关系。有了这个关系,才有了多态的特性。extends
不要为了获取其他类的功能,简化代码而继承;必须是类与类之间有所属关系才可以继承。
注意:Java只支持单继承,不支持多继承。 因为多继承容易带来安全隐患。但是支持多层继承。
查阅父类功能,创建子类对象使用功能。
子类特点
类中成员:变量、函数、构造函数。
变量
当父类和子类出现非私有的同名成员变量时,优先使用子类变量。子类要访问本类的变量,用this。子类要访问父类的变量,用super。
this是本类的引用,super是父类的引用。
函数
当父类和子类出现非私有的同名函数(返回值也需要一致)时,当子类对象调用该函数时,会运行子函数的内容。即重写(覆盖)。
1.子类覆盖父类,必须保证子类权限大于等于父类权限(private不能覆盖public),才可以覆盖,否则编译失败。2.静态只能覆盖静态。
构造函数
在对子类对象进行初始化时,父类的构造函数也会执行,因为子类的构造函数会默认第一行有一条隐式的语句 super();如果要访问父类中指定的构造函数,可以通过手动定义super语句来指定。
PS:子类的构造函数第一行也可以通过手动指定this语句来访问本类中的其他构造函数。因为子类中至少有一个构造函数会访问父类中的构造函数。
1 | class Fu{ |
final
可以修饰类、函数、变量;被final修饰的类和函数不能被继承;
被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。常量的书写规范所有字母大写。
抽象类
多个类出现相同函数名,但是函数主体不同时,可以只抽取函数名称,而不抽取功能主体。
1 | abstract class Student{ |
抽象类特点
抽象方法一定在抽象类中;抽象类可以有非抽象方法;抽象类不可能用new创建对象;如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
PS:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
接口
初期理解:可以认为是一个特殊的抽象类。要求其类中的方法都是抽象的。用interface来定义。
interface的对变量的修饰符为:public static final;对函数的修饰符为public abstract。均可以省略。
1 | interface Inter |
因为接口中均为抽象方法,因此不可以创建对象。需要被子类实现,将接口中的抽象方法全部覆盖后,子类才能实例化。
这时,子类的修饰符不用比接口类大。
1 | interface Inter |
接口可以进行多实现。
1 | interface InterA |
接口与接口之间也是继承关系,但是接口和接口之间支持多继承
接口的使用
抽象类是核心属性或者功能,而接口是扩展属性或者功能。
1 | abstract class Student |
多态
事物存在的多种体现形态
1 | abstract class Animal{ |
体现:
父类的引用指向了自己的子类对象;父类引用可以接收自己的子类对象。
1 | Animal c = new Cat(); |
前提:1.类与类之间有关系(继承、实现);2.存在覆盖。
特点:提高代码的复用性,但是只能使用父类的引用访问父类中的成员。
由于Animal a =new Cat();
是向上转型。即将a转化为animal,则不能使用Cat类中的特有属性。因此需要强制转换。
1 | Animal a = new Cat();//向上转型 |
上述例子的function方法可以单独封装为一个类:
1 | class Doanimal{ //执行类 |
特点:
对于非静态成员函数而言 编译时期:参阅引用型变量所属的类中是否有调用的方法。运行时期:参阅对象所属的类中是否有调用的方法。
对于变量和静态成员而言 编译和运行都参考引用型变量所属的类。
1 | class Fu |
接口和抽象例子
1 | class MainBoard |
这个例子中,MainBoard类的成员函数调用了接口类PIC。当需要NetCard时,将PIC实现,并在MainBoard对象中调用runPIC函数即可。当需要SoundCard时,重复上述过程即可。扩展性极强。[]
Object的equals()的覆写
1 | class Example{ |
*内部类(不常用)
1.内部类可以直接访问外部类中的成员,包括私有。因为内部类中持有一个外部类的引用,格式为 外部类名.this
2.外部类要访问内部类,必须建立内部类对象。
3.内部类可以被静态修饰。被static修饰后,只能访问外部类的静态成员。此时调用内部类中的非静态函数就可以通过new Outer.Inner().method()
。调用静态函数则可以通过Outer.Inner.method()
。同时,非静态内部类不能定义静态成员。
4.外部类中的静态函数访问内部类时,内部类也需要是静态的。
1 | class Outer |
局部内部类
1 | class Outer |
内部类定义在局部时,不可以被成员修饰符修饰;可以直接访问外部类中的成员,但是不可以访问它所在的局部中的变量,除非被final修饰。
匿名内部类
匿名内部类
1 | class AbsDemo{ |
其中,第6-11行是在定义该内部类,第13行是创建内部类对象。如果要将内部类变为匿名内部类,则考虑无法通过具体的类名称来使用内部类。因此匿名内部类的代码如下
1 | class AbsDemo{ |
23.40