java基础
1.字符串
String 字符串常量,常量池中
- final类型,每次改变都是重新分配对象,因此频繁的改变String类型会导致过多的无用对象,引起频繁的GC;
- 不经常修改的变量可以使用String,比如model类属性;
String好处
- 实现常量池:相同字串相同常量,节省了空间;对比StringBuilder相同字串占用两个堆内存;
- String对象创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串;
StringBuffer 线程安全
StringBuilder,java堆中
StringBuilder
存储值的数组在其继承的抽象类AbstractStringBuilder
中,构造参数既可以指定其数组容量大小,或者默认为16抑或String
类型构造参数长度值加16;
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
public StringBuffer() {
super(16);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
速度:StringBuilder>StringBuffer>String
2.字符串方法
- String的
trim()方法
:删除头尾空白符的字符串; - String的
intern()
方法:如果常量池存在字符串对象,则返回常量池新对象的引用;不存在则将字符串对象放进常量池然后返回此对象的引用; - new String("aa")返回的是java堆中的对象;
String chinese=new String("杜艮魁");//java堆
System.out.println(chinese.intern()==chinese);
2.5 String.toCharArray()返回的数组是有序的
char[] cs=a.toCharArray();//返回的序列是有序的
for (char c:cs) {
System.out.print(c+"\t");
}
//output:c s
3.同一行声明顺序
// int b=a,a=1; 报警a没有被初始化
int a=1,b=a;
a=2;
System.out.println(b);//output 1;
4. 异或^
异或即相同时为1,不同时为0。使用异或可以快速交换两个数的值:
a=a^b;
b=a^b;
a=a^b;
5.自增自减陷阱
===
int test=2;
while(test--!=0){//fixme: 等于0时判定条件并没有结束,而是继续做自减操作;里边内容进行了2次
System.out.println("tast");
}
System.out.println(test);
/**
* output:
* test
* test
* -1;
*/
6. 内部类泛型标识
以下,内部类和外部类的数据类型不一定要是一样的。
public class TestThreadPoolExecutorStop<E> {
E val;
static class Node<E>{
E va;
public Node(E va) {
this.va = va;
}
}
public TestThreadPoolExecutorStop(E val) {
this.val = val;
}
}
7. 类变量和方法变量
类变量不进行初始化会设置默认值,比如基本类型的0、FALSE;
方法变量必须进行初始化,否则编译不能通过。
8. 相等比较和大小比较
==
、!=
操作要快与>
、<
,猜测前者比较hasCode
即可,后者还要进行一些逻辑运算。
9. 父类私有变量不能被子类继承
10. 时刻记住main方法是静态方法
11. 多态
不同类型引用的多态方法能够通过编译并运行,而且是那个参数引用就调用那个方法:
public class Abstract {
public void func(Object a){
System.out.println("Obj");
}
public void func(Father a){
System.out.println("father");
}
public void func(Son a){
System.out.println("son");
}
public static void main(String[] args) {
Abstract a=new Abstract();
Father father=new Son();
a.func(father);
//output:father
}
}
16.父类静态代码块(静态变量)、代码块(全局变量)、构造器、子类静态代码块(静态变量)、代码块(全局变量)和构造器的执行顺序;
静态域总是在虚拟机启动时被创建执行,非静态域在创建对象时被创建执行,因此:
父类静态域、子类静态域。
如果创建对象的话:
父类非静态域、父类构造器,子类非静态域,子类构造器。
class VaralbleTest{
public VaralbleTest(String str) {
System.out.println(str);
}
}
class ConFather {
static{
System.out.println("static conFather");
}
static VaralbleTest tt=new VaralbleTest("static variable");
//代码块和方法对象是同等优先级的,哪个在前边那个先执行
{
System.out.println("non-static conFather");
}
VaralbleTest test=new VaralbleTest("non-static variable");
public ConFather() {
System.out.println("father constrac");
}
}
public class ConstractorStatic extends ConFather {
static{
System.out.println("static son");
}
{
System.out.println("non-static son");
}
public ConstractorStatic() {
System.out.println("son constractor");
}
public static void main(String[] args) {
new ConstractorStatic();
//output:
static conFather
static variable
static son
non-static conFather
non-static variable
father constrac
non-static son
son constractor
...如果main方法没有代码,output:
static conFather
static variable
static son
}
}
重要补充
多态方法即导出类重写父类的方法:
如果这个方法在父类构造器中使用,则调用的是子类重写后的方法;
假若这个方法调用了子类某个变量,则这个变量因为还未在导出类中用其初始化方法,此时分配给变量的存储空间初始化成二进制的0;
示例如下:
class father{
public father() {
func();
}
void func(){ }
}
class son extends father{
int tag=1;
public son(int tag) {
// System.out.println("tag = "+tag);这里默认调用了父类的构造方法;
this.tag = tag;
System.out.println("tag = "+tag);
}
@Override
void func() {
System.out.println("tag = "+tag);
}
}
public class Demo02 {
public static void main(String[] args) {
new son(1);
}
}
output:
tag = 0//分配给对象的存储空间初始化为二进制的零;
tag = 1
17.父子类同名变量
子类不会覆盖父类变量,哪个类型的引用就会调用哪个类的变量,而且子类不定义的话调用父类变量。
class FatherT{
final int a=1;
}
public class TestFatherFinalVaria extends FatherT{
int a=2;
public static void main(String[] args) {
FatherT tt=new TestFatherFinalVaria();
System.out.println(tt.a);
System.out.println(((TestFatherFinalVaria) tt).a);
//output:1 2
//如果把子类同名变量注释后,输出结果为 1 1
}
}
1.<<、>>、>>>
<<
左移,相当于乘2;>>
有符号右移,正数左边全部补0,负数左边全部补1;>>>
无符号右移,不管正数还是负数左边全部补0。
int posNum=14;
int negNum=-14;
System.out.println("数的二进制表示");
System.out.println(posNum+":"+Integer.toBinaryString(posNum));
System.out.println(negNum+":"+Integer.toBinaryString(negNum));
System.out.println("左移:左移n位相当于乘2^n。正负数低位都补0");
System.out.println(Integer.toBinaryString(posNum)+":"+Integer.toBinaryString(posNum<<2));
System.out.println(Integer.toBinaryString(negNum)+":"+Integer.toBinaryString(negNum<<2));
System.out.println("有符号右移,正数高位都补0,负数高位补1");
System.out.println(Integer.toBinaryString(posNum)+":"+Integer.toBinaryString(posNum>>2));
System.out.println(Integer.toBinaryString(negNum)+":"+Integer.toBinaryString(negNum>>2));
System.out.println("3.无符号右移,正负数高位都补0");
System.out.println(Integer.toBinaryString(posNum)+":"+Integer.toBinaryString(posNum>>>2));
System.out.println(Integer.toBinaryString(negNum)+":"+Integer.toBinaryString(negNum>>>2));
output:
数的二进制表示
14:1110
-14:11111111111111111111111111110010
左移:左移n位相当于乘2^n。正负数低位都补0
1110:111000
11111111111111111111111111110010:11111111111111111111111111001000
有符号右移,正数高位都补0,负数高位补1
1110:11
11111111111111111111111111110010:11111111111111111111111111111100
3.无符号右移,正负数高位都补0
1110:11
11111111111111111111111111110010:111111111111111111111111111100