11.1学习笔记
<font color=gray><font size=7>缓存池</font></font>
public void test(){
Integer a = new Integer(1);
Integer b = new Integer(1);
// false
System.out.println(a==b);
Integer c = 1;
Integer d = 1;
// true
System.out.println(c==d);
// false
System.out.println(a==c);
Integer e = 128;
Integer f = 128;
// false
System.out.println(e==f);
}
任何使用new关键字new出来的对象都是不同的,所以 System.out.println(a==b);为false,但是直接将数值赋值给整型变量的时候,会先判断值是否在缓存池装那个,如果在的话就直接返回缓存池中的内容。
在<font color=red> java8 </font>中Integer缓存池的大小是<font color=purple><font size=5> -128-127 </font></font>
基本类型对应的缓存池如下:
boolean values true and false
all byte values
short values between -128 and 127
int values between -128 and 127
char in the range \u0000 to \u007F
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
<font color=gray><font size=75>常量池</font></font>
常量池(constant pool)专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据,他包括了类,方法,接口中的常量,还包括字符串常量
String s1 = "疯狂java";
String s2 = "疯狂";
String s3 = "java";
String s4 = "疯狂" + "java";
String s5 = "疯" + "狂" + "java";
String s6 = s2 + s32;
String s7 = new String("疯狂java");
System.out.println(s1==s4);
System.out.println(s1==s5);
System.out.println(s1==s6);
System.out.println(s1==s7);
输出结果
true
true
false
false
当Java程序直接使用"疯狂java"的字符串直接量(包括其他在编译时就可以计算出来的字符串值例如s4,s5)时,JVM将会
使用常量池来管理这些字符串;当使用new String("疯狂java")时,JVM会先使用常量池来管理"疯狂java"直接量,再调用String的构造器
来创建一个新的String对象,新创建的String对象被保存在堆中,new String("疯狂java") 这条语句产生了两个字符创对象。
JVM常量池保证相同的字符串直接量只有一个,不会产生多个。s1,s4,s5所引用的字符串可以在编译时期就确定下来,因此他们豆浆引用常量池中的一个字符串对象
<font color="blue"><font size=3>s6=s1+s2 s6后面的字符串值不能在编译时就确定下来,不能引用常量池中的字符串</font></font>
<font color=gray><font size=7>关键字</font></font>
<font color=green><font size=6>final</font></font>
final关键字可以用来修饰类、变量和方法
- 修饰变量:变量一旦获得了初始值就不会被改变 <font color=BlueViolet> final修饰的成员变量必须有程序员显示的指定初始值</font>
- 成员变量是随着类的初始化,或者对象的初始化而初始化的,当类初始化时,系统会为该类的类变量分配内存,并分配默认值
当创建对象时,系统回味该对象的实例变量分配内存,并分配默认值。也就是说,当执行静态初始化块、构造器可以对类变量赋初始值,当执行普通的
初始化块、构造器中指定初始值。因此,成员变量的初始值可以在定义该变量的时候指定默认值,也可以在初始化块,构造器中指定初始值。
对于final修饰的成员变量,一旦有了初始值就不能被重新复制,如果没有定义成员变量的指定初始值,也没有在初始化块、构造器中为成员变量指定初始值
那么这些成员变量的值将一直是系统默认分配的0、\u0000、false或null。也就是缺了存在的意义。 -
final成员变量在初始化之前不能直接访问,但是可以通过方法访问——java设计缺陷
对于基本类型,final使数值不变;
对于引用类型,final使引用值不变,但是引用所指定的对象是可以改变的 - 宏变量
使用final修饰
在定义该final变量时制定了初始值
该初始值可以在编译时就被确定下来
System.out.println(s1==s6); 想要输出true,将s1 和 s6 定义为final即可。这样编译器在编译阶段就可以确定s2和s3的值
然后就会让s6指向字符串中缓存的值
- final修饰的方法不可以被重写
- final修饰的类不可以有子类
<font color=gray><font size=7>不可变类</font></font>
不可变类的意思就是创建该类的实例以后,该实例的实例变量是不可以改变的。java的8个包装类和java.lang.String类都是不可变类
- 自定义不可变类
使用private 和 final修饰成员变量
提供带参数的构造器(或返回该实例的类方法),用于根据传入参数来初始化类里的成员变量。
仅为该类的成员变量提供gettter方法,不要提供setter方法因为普通方法无法修改final修饰的变量成员
重写Object类中hashCode和equals方法。
<font color=gray><font size=7>抽象类</font></font>
抽象类和抽象方法必须用abstract关键字来声明。
含有抽象方法的类是抽象类,抽象类中可以没有抽象方法
- 规则
抽象类抽象方法必须用abstrac关键字修饰,抽象方法中不能有方法体
抽象类可以包含正常类的五个成员(成员变量,方法(普通或者抽象方法),构造器(主要是给子类调用),初始化块,内部类)
含有抽象方法的类(直接定义抽象方法,继承抽象类,但是没有完全实现抽象方法,实现接口,但是没有完全实现接口中包含的抽象方法),只能被定义为抽象类
public abstract class Shape {
{
System.out.println("执行shape的初始化块");
}
private String color;
public Shape() {
System.out.println("执行shape的无参数构造器");
}
public Shape(String color) {
System.out.println("执行shape的构造器");
this.color = color;
}
public abstract double calPerimeter();
public abstract String getType();
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
public class Triangle extends Shape {
private double a;
private double b;
private double c;
public Triangle(String color, double a, double b, double c) {
super(color);
this.setSides(a, b, c);
}
@Override
public double calPerimeter() {
return a + b + c;
}
@Override
public String getType() {
return "三角形";
}
private void setSides(double a, double b, double c) {
if (a >= b + c || b >= c + a || c >= a + b) {
System.out.println("两边之和必须大于第三边");
return;
}
this.a = a;
this.b = b;
this.c = c;
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
this.radius = radius;
}
@Override
public double calPerimeter() {
return 2 * Math.PI * radius;
}
@Override
public String getType() {
return getColor()+"圆形";
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
}
public void test3(){
Shape s1 = new Triangle("黑色",3,4,5);
Shape s2 = new Circle("黄色",3);
System.out.println(s1.getType());
System.out.println(s1.calPerimeter());
System.out.println(s2.getType());
System.out.println(s2.calPerimeter());
}
输出结果:
执行shape的初始化块
执行shape的构造器
执行shape的初始化块
执行shape的无参数构造器
三角形
12.0
null圆形
18.84955592153876
<font color=gray><font size=7>接口</font></font>
接口是从多个相似类中抽象出来的规范,接口不提供任何实现,接口体现的是规范和实现分离实际哲学
接口定义的是一种规范,因此接口不能包含构造器和初始化块定义。接口可以包含
- 成员变量 只能是静态常量 默认为接口里定义的成员变量添加public static final修饰符
- 方法 只能是抽象方法,类方法,默认方法或私有方法 加粗方法必须有实现 ,默认方法没有static修饰,因此不能直接使用接口来用调用默认方法,需要使用接口的实现类的实例来调用这些默认方法。
- 内部类 内部接口,内部枚举默认都采用pulibc static两个修饰符,不管定义是是否制定,系统会自动使用pulic static 对他们进行修饰
<font color=Brown>接口可以多继承</font>
interface A {
int a = 100;
void testA();
}
interface B{
int b = 200;
void testB();
}
interface C extends A,B{
int c=300;
void testC();
}
public class InterfaceExtendsTest{
public static void main(String[] args) {
System.out.println(C.a);
System.out.println(C.b);
System.out.println(C.c);
}
}
输出:
100
200
300