目录
- 继承
- static方法是否可以被重写
- 对象包装器与自动装箱
- 总结
继承
下面的内容的内容适合对于
java
的基础语法有一定的了解的用户。本篇的内容将从Java继承章节中的一些容易出错的知识点进行归纳。如果你对于
Java
的基础语法有所了解,那么本篇文章将比较适合你。
继承中值得体会的几句话,如果你在看下面每个知识点的时候,可以马上再脑海中勾勒出该知识点的大致结构,那么说明你对于Java的基础知识掌握的还不错
- String类是final类,这意味着不允许任何人定义String的子类。换言之,如果有一个String引用,它引用的一定是一个String对象,而不可能是其他类的对象。
- 进行强制类型转换的唯一原因是:要在暂时忽视对象的实际类型之后使用对象的全部功能
- 将一个值存入变量时,编译器将检查你是否承诺过多。如果将一个子类的引用赋给一个超类变量,编译器是允许的。但将一个超类的引用赋给一个子类变量时,就承诺过多了。必须讲行强制类刑转换这样才能够通讨云行时的检杏
- 特别的,父类中声明为private的属性和方法,子类继承以后,仍然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
static方法是否可以被重写
父类的静态方法是不能被子类重写的。
在下面的代码中一个父类和一个子类,类中有两个方法,一个静态方法和普通方法。子类的方法和父类的方法完全一样。为了区分,只是打印语句的内容不一样。
class A{
public void method1(){
System.out.println("父类的普通方法");
}
public static void method2(){
System.out.println("父类的静态方法");
}
}
class B extends A{
public void method1(){
System.out.println("子类的普通方法");
}
public static void method2(){
System.out.println("子类的静态方法");
}
}
class Test{
public static void main(String[] args) {
A a = new B();
a.method1();
a.method2();
B b = new B();
b.method2();
}
}
查看运行结果
在测试代码中创建了两个对象,A a = new B();
为父类的引用指向子类的对象。和B b = new B()
,子类的引用指向子类的引用。
从结果可以看出来在通过多态的方式调用a.method()
时的结果为父类的静态方法
,即表明了方法method2
没有被重写。
对于上面的的结果,我们需要了解了一下静态方法。
静态方法在编译之后所分配的内存会一直存在(不会被回收),直到程序退出内存才会释放这个空间。在外部调用静态方法时,可以使用”类名.方法名”的方式,也可以使用”对象名.方法名”的方式。而实例方法只有后面这种方式。
静态方法在编译期间就会分配内存,直到程序退出才会释放,实例方法是在创建对象时才分配相应的内存,对于父类引用指向子类对象,可以调用二者共同的方法、变量。
因此即便是在子类对象中定义一个于父类一模一样的静态方法,但是这个静态方法属于子类本身,在内存中会分配两块控件去存放这两个静态变量,因此静态方法不存在重写。
- 如果父类时静态的方法而子类和父类同名同参数的方法时非静态的将报错
最后的总结
子类和父类中同名同参数的方法要么都声明为非static,要么都声明为static的.(但是这个不是重写)
对象包装器与自动装箱
介绍
有时,需要将
int
这样的基本类型转换为对象
。所有的基本类型都有一个与之对应的类。
例如,Integer类对应基本类型int。
通常,这些类称为包装器( wrapper)。
这些包装器类有显而易见的名字:Integer、Long、Float、Double、Short、Byte、Character和 Boolean(前6个类派生于公共的超类Number)。
包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时,包装器类还是final,因此不能派生它们的子类。
假设想要定义一个整型数组列表。遗憾的是,尖括号中的类型参数不允许是基本类型也就是说,不允许写成ArrayList。这里就可以用到Integer包装器类。我们可以声明个Integer对象的料组列寿
var list = new ArrayList<Integer>();
或者写成这样
ArrayList<Integer> list = new ArrayList<>();
警告:由于每个值分别包装在对象中,所以 ArrayList的效率远远低于int[]数组。因此,只有当程序员操作的方便性比执行效率更重要的时候,才会考虑对较小的集合使用这种构造。
幸运的是,有一个很有用的特性,从而可以很容易地向ArrayList添加int类型的元素。下面这个调用
list.add(3);
将自动地变换成list.add(Integer.value0f(3));
这种变换称为自动装箱( autoboxing)。
注释:大家可能认为自动包装(autowrapping)与包装器更一致,不过“装箱"(boxing)这个词源于C#。
相反地,当将一个Integer对象赋给一个int值时,将会自动地拆箱。也就是说,编译器将以下语句:
int n = list.get(i);
转换成int n = list.get(i).intValue( ) ;
自动地装箱和拆箱甚至也适用于算术表达式。例如,可以将自增运算符应用于一个包装器引用:
Integer n = 3;n++;
编译器将自动地插人一条对象拆箱的指令,然后进行自增计算,最后再将结果装箱。大多数情况下容易有一种假象,认为基本类型与它们的对象包装器是一样的。但它们有一点有很大不同:同一性。大家知道,==运算符可以应用于包装器对象,不过检测的是对象是否有相同的内存位置,因此,下面的比较通常会失败:
Integer a = 1000;
Integer b = 1000;
if (a == b) . . .
不过,Java实现却有可能(如果选择这么做)让它成立。如果将经常出现的值包装到相同的对象中,这种比较就可能成功。这种不确定的结果并不是我们所希望的。解决这个问题的办法是在比较两个包装器对象时调用equals方法。
注释:自动装箱规范要求boolean、byte、char<=127,介于-128和127之间的short和int被包装到固定的对象中。例如,如果在前面的例子中将a和b初始化为100,那么它们的比较结果一定成功。
关于自动装箱还有几点需要说明。首先,由于包装器类引用可以为null,所以自动装箱有可能会抛出一个`NullPointerException异常:``
Integer n = null;
System.out.println(2 * n);// throws NullPointerException
最后强调一下,装箱和拆箱是编译器要做的工作,而不是虚拟机。编译器在生成类的字节码时会插入必要的方法调用。虚拟机只是执行这些字节码。
使用数值包装器通常还有一个原因。Java设计者发现,可以将某些基本方法放在包装器中,这会很方便,例如,将一个数字字符串转换成数值。
要想将字符串转换成整型,可以使用下面这条语句:int x = Integer.parseInt(s);这里与Integer对象没有任何关系,parseInt是一个静态方法。但Integer类是放置这个方法的一个好地方。
Integer类中常用的方法
总结
在本篇内容中主要时对于继承章节中的static方法是否可以被重写以及对象包装器与自动装箱的两个继承中容易忽略,同时对于我来说比较容易出错的知识进行了详细的分析和总结。