Java 笔记
每个java源文件只能有一个public类型的类,并且此类要和文件名相同。
实例变量永远都会有默认值,即使没有显式赋值。
默认值:
int 0
float 0.0
boolean false
引用 null
==
对于primitive主数据类型来说,是进行字节比较,而引用类型的话,则是比较是否引用的是同一个对象。java中跨类型转换(比如从String到int),需要调用内建类来完成转换。比如,
Integer.parseInt("3")
for-in循环来遍历的时候,调用的只是副本
java的随机数由Math类的random()方法提供,产生一个介于0到1之间的小数。
类似
(int)
,成为cast运算符,即强制类型转换。关于抽象类与抽象方法
Java天生支持(运行时多态),而C++则必须用
virtual
关键字修饰函数才能实现。C++的纯虚函数才相当于Java的抽象方法。
猜想:因为Java强制面向对象,所以不会有全局的函数,所以可能就不需要像C++那样来区分全局函数和成员函数。同理纯虚函数和函数声明可能也有类似的关系。
扫描二维码关注公众号,回复: 49814 查看本文章猜想:非抽象类的所有成员都会被“构造出实体”,所以非抽象类才不能有抽象方法。Java这种用抽象类来约束抽象方法的行为,可能比C++那种反过来约束要好一些。
关于继承与多态
- java不允许多继承,所以一个类只可以继承(extends)一个普通类。但同时可继(implements)承多个接口。
- java声明为父类的引用可以被赋值子类的实体,但是只能调用父类的方法。
抽象类与接口
- 抽象类允许有非抽象函数,即允许有被实际定义了的函数。
- 接口则不允许有非抽象函数。
- 子类只能继承一个抽象类,但可以继承多个接口。
- 接口必须被实现,而抽象类可以被抽象类继承。
- 类继承的概念是垂直的,而接口实现的概念是平行的。哈士奇类继承狗类,狗类继承动物类,哈士奇必是动物。
所以使用接口必不会出现钻石继承,因为任何一个接口必没有父类(接口)
- 而又由于接口必被实现,不能有父接口的存在,所以根本堆叠不起来,也就不会有垂直一说。所以,哈士奇类如果用接口来完成的话就是同时实现狗接口和动物接口。但这是不合理的,因为狗都是动物,它们是自然存在堆叠关系的。所以,哈士奇类实现犯二接口和嚎叫接口是合理的。
可以看出,类和接口虽然类似但是根本不是同一种东西。类是确定的一以贯之的,就像商城里商品的分类,而接口是灵活的描述性的,就像商品的标签
关于成员访问权限
- 在java中,子类不能将父类成员方法的权限缩小,但可以放大(如protected变为public)。
- 而成员变量的权限则不能被修改。
因为假设一个接口定义了一套规则,保证一个实现此接口的任何一个子类都能有此方法可调用,但是若被子类改成private就尴尬了
关于静态和非静态方法
- 静态方法是属于类的,不属于单独的对象。
- 非静态方法是属于每一个对象的,不属于类。
其实,某种意义上说,静态方法就是过程式编程中的函数,即就想要某个特定的功能,而不属于什么客观事物关系。即使属于某个类也只是简单的分类,而没有逻辑上的堆叠关系,也就是说静态方法前的类名,一定意义上起了一个名字空间的作用。
- 非静态方法可以调用静态方法,而静态方法则不能(直接)调用非静态方法(不论本类内外)。
- 本类中非静态方法可以调用非静态方法,但不能(直接)调用其他类的非静态方法。
- 静态方法任何时候都可以互相调用。
其实以上问题就是个实例化的问题:非静态方法除了在本类非静态方法中,在其他任何地方的调用,都需先把类实例化为对象再调用。
关于方法调用
有个很有意思的对比:
代码1:
public class ClassTest {
public static void main(String[] args){
A a = new B();
a.get();
}
}
class A{
int a = 0;
public void get(){
System.out.println(a);
}
}
class B extends A{
int a = 1;
}
输出: 0
代码2:
public class ClassTest {
public static void main(String[] args){
A a = new B();
a.get();
}
}
class A{
int a = 0;
public void get(){
System.out.println(a);
}
}
class B extends A{
int a = 1;
public void get(){
System.out.println(a);
}
}
输出: 1
这说明了2个(其实是显而易见的)问题:
- 用父类的引用变量去操纵子类的对象时,方法优先用子类覆盖的版本(符合逻辑)。
而第一个例子也说明,实例变量的作用域只在类中。所以,本类的方法只能访问本类的变量(不附加其他任何条件的情况下)。
关于常量的定义
我的老师说,用static修饰的变量就是常量,其实不是的,因为它可以被子类覆盖而且还可以被静态方法修改。
只有用final和static两个修饰符修饰的变量,才可以当常量使用。
关于覆盖与重载
覆盖是指重写一个与父类(或实现的接口)中方法形式(返回值和参数以及函数名)完全一致的新方法。
- 而重载则是写一个与已存在方法同名但不同参数表的新方法。
所以下面这段代码既不是覆盖也不是重载,根本不会通过编译
class A{
int a(){
...
}
}
class B extends A{
double a(){
...
}
}
持续更新中…