java基础-《JAVA语言程序设计与数据结构》笔记
最近差不多把java语言部分学习了一遍,这里把之前书上做标记的内容记录一下,巩固基础。
一、 类和对象
1. java默认值:引用类型数据域为null,数值类型数据域的默认值是0,boolean类型数据域的默认值为false,char类型数据域的默认值为“\u0000”。
其中,java没有给方法中的局部变量赋默认值。
2. 可见性修饰符:private修饰符只能应用在类的成员上,而public可以用在类或类的成员上。在局部变量上使用修饰符public和private都会导致编译错误。
3.变量作用域:实例变量和静态变量的作用域是整个类。
4.this语句:java规定了,在构造方法中语句this应在任何其他可执行语句之前出现。
5.包装类:java中处于对性能的考虑,基本数据类型不作为对象使用。但为了方便,在java.lang包里面提供了各基本数据类型对应的包装类。
包装类没有无参构造方法,可以使用基本数据类型值或表示数值的字符串来构造包装类。如:new Double(4.2)或new Double("4.2")。
基本类型值与其对应的包装类间的转换过程称为“装箱”或“拆箱”。
6.String类为:String变量存储的是对不可变的String对象的引用,String对象里存储的才是字符串的值。但约定俗成,经常使用术语字符串来表示String变量、String对象和字符串的值。
7. 字符串与数值或字符间的相互转化:Double.parseDouble("5.44");String.valueOf(5.44)。
8.构造方法链:在任何情况下,构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法,这个过程持续到沿着这个继承层次结构的最后一个构造方法被调用为止。
这里可以用super语句来理解,若子类构造方法中没有super语句,编译器会自动在第一行处“添加一行super语句”。
所以,在设计一个会被继承的类时,最好提供一个无参构造方法,避免出现这种情况:子类Apple没有显式定义构造方法,其在实例化时会在调用自己的默认无参构造方法之前调用父类Fruit的无参构造方法,但父类由于定义了有参构造方法,编译器就不会提供默认的无参构造方法,调用失败,编译就会出错。代码如下:
1 public class Apple extends Fruit { 2 } 3 4 class Fruit { 5 public Fruit(String name) { 6 System.out.println("Fruit's constrctor is invoked"); 7 } 8 }
此外,super语句不仅可以调用父类的构造方法,也可以调用父类的普通方法。
需要注意的是,只有隐式调用子类构造方法(此处三种情况均可:a.显示给出有参构造方法,b.显示给出无参构造方法,c.未给出构造方法,编译器给出默认无参构造方法)时,
即子类实例化时,才会调用构造方法链;显式调用子类构造方法时(如super语句),就不会调用父类的无参构造方法。
9.方法重写:存在于继承中,即子类重写父类的方法。重写的方法间必须具有一样的签名(函数名和参数列表必须完全相同),但返回类型可以一样或兼容,
兼容即子类重写的方法的返回类型时父类被重写的方法的返回类型的子类型。java语法中提供重写标注,以避免错误。
public class Circle extends GeometricObject { // other methods @override public String toString(){ return super.toString() + "\nradius is " + radius; } }
其中,静态方法不能被重写。因为若父类的静态方法在子类中被重新定义,那么父类的该静态方法就会被隐藏。但仍然可以使用(父类名.静态方法名)调用。
10.方法重载:函数名必须完全相同,但参数列表不同。
所有的java类都继承自Object类,而Object有一个toString()方法。
11.多态:由于子类“大于”父类,若A是B的父类,那么B就包含A,java中就可以用A类型的变量来引用B的对象,此时编译器就会自动将B中不属于A的部分忽略。
多态意味着父类型的变量可以引用子类型的对象。即在新建对象实例时,声明类型时父类型,但实际类型是子类型。
动态绑定:引用变量调用方法时,由其实际类型决定调用哪个具体的方法。JVM会从子类一直往根类(Object类)寻找该方法,一旦找到一个实现,就停止查找,调用即可。
但需要注意的是,虽然具体调用的哪个方法是由变量的实际类型决定,由JVM在运行时动态绑定方法的实现。但,引用变量的声明类型决定了编译器编译时匹配哪个方法。
12.显式转换:将父类引用变量显式转换成对应子类的引用类型,从而使编译器明白代码的意图。
显式转换的目的在于避免编译错误的发生,因为引用变量的声明类型决定了在编译阶段匹配哪个方法,而父类型有可能并不存在子类型中调用的方法。
此外,对象成员访问操作符的优先级高于类型转换操作符的优先级,体现在代码中如下:
((Circle)object).getArea();
对基本类型值进行显式类型转换时,语句会返回一个新的值,而原变量的值不变;但引用变量的显式转换则并不会创建一个新的对象:
1 int age =45; 2 byte newAge = (byte)age; // newAge会得到一个新创建的值。 3 4 Object o = new Circle(); 5 Circle c = (Circle)0; // 引用变量o和c指向同一个对象。没有新建任何对象
13. equals方法和比较操作符==:比较操作符用来比较两个基础数据类型的值是否相等或者两个引用变量的对象地址是否相同,即是否是指向同一个对象。
Object类中equals方法的默认实现为:
1 public boolean equals(Object obj) { 2 return (this == obj); 3 }
然而。equals方法在JAVA API的许多类中都被重写,用于比较两个对象的内容是否相等。如java.lang.String和java.util.Date。
由于重写时应的函数签名应完全相同,所以重写的equals方法接收形参须为Object类型,即:
1 @Override 2 public boolean equals(Object o) { 3 if (o instanceof Circle) 4 return radius == ((Circle)o).radius; 5 else 6 return false; 7 }
14. 可见性修饰符
修饰符 | 同一类中 | 同一包中 | 不同包的子类中 | 不同包非子类中 |
public | 1 | 1 | 1 | 1 |
protected | 1 | 1 | 1 | 0 |
默认 | 1 | 1 | 0 | 0 |
private | 1 | 0 | 0 | 0 |
15. 构造方法总结:
构造方法用于构造类的实例,不同于类的属性和方法,子类不会继承父类的构造方法,它们只能通过super语句从子类的构造方法中显式调用。
当然,构造方法也可以调用重载的构造方法或其父类的构造方法,该调用必须在构造方法的第一条语句出现。
若没有此调用,编译器会把super()默认左右构造方法的第一条语句,从而调用其父类的无参构造方法。
二、异常处理
1.浮点数除以0是不会产生异常的。
2.异常处理的根本优势在于将被调用的方法中的检测错误从调用者的处理错误中分离出来。
3.java中的异常类分为三种类型:系统错误、异常和运行时异常。
系统错误是有JVM抛出的,用Error类表示。
异常用Exception类表示,包括ClassNotFoundException类、IoException类等等。
运行时异常用RuntimeException类表示,描述的是代码的错误。如ArithmeticException类、NullPointerException类、IndexOutOfBoundsException类、IllegalArgumentException类等等。
其中运行时异常和系统错误及其它们的子类都称为免检异常,所有其他的异常都称为必检异常。java要求所有必检异常须在方法头中声明并且使用try catch块处理它们。
因为任何代码都有可能发生免检异常,所有java对它们没有强制要求。
需要注意的是,若在父类的方法中没有声明必检异常,则在其子类中对其重写时就不能再声明异常。
4.异常捕获:由于各种异常类可以从一个共同的父类中派生,则一个catch块可以捕获一个父类的异常对象时,它也能捕获那个父类的所有子类的异常对象。
所以, catch块的顺序十分重要,若父类异常的catch块在其子类异常的catch块前面,此时子类的catch块就形同虚设,就会导致编译错误。
5.链式异常:将catch块中捕获的异常继续向上抛出。代码如下:
1 catch(Exception ex) { 2 throw new Exception("New info from method1", ex) //此处抛出了两个异常 3 }
6. 自定义异常类时,最好使其成为必检异常,这样编译器就可以强制捕获这些异常。
7. try-with-resourse语句可以避免错误的同时简化代码catch块。
三、抽象类和接口
1.包含抽象方法的类肯定是抽象类,但抽象类可以不全是抽象方法。抽象类的构造方法定义为protected。抽象方法是非静态的。
即使子类的父类是具体的,这个子类也可以是抽象的。抽象类不能实例化。
2.接口时一种与类相似的结构,只包含常量和抽象方法,以及默认方法和静态方法。
接口中的所有数据域都是public static final修饰的;接口中的所有方法都是public abstract修饰的。
书写接口代码时java允许省略这些修饰符,但在子类实现时方法必须定义为public的。
此外,java8开始,引入了默认接口方法和公有的静态方法。如:
1 public interface A { 2 // 接口中的默认方法 3 public default void doSomething() { 4 System.out.println("Do something"); 5 } 6 7 // 接口中的公有静态方法 8 public static int getValue() { 9 return 0; 10 } 11 }
3. Object类中的clone方法自动对所有的数据域进行浅复制。
4.一个类仅能继承一个父类,但却可以实现一个或多个接口;一个接口可以继承一个或多个接口,但不能继承类。
变量 | 构造方法 | 方法 | |
抽象类 | 无限制 | 构造方法链,不能new | 无限制 |
接口 | 所有变量都必须为public static final | 没有构造方法,不能new | 可以包含public的抽象实例方法、public的默认方法和public的静态方法 |
三、泛型
四、多线程
posted on 2019-08-23 22:46 leodowhat 阅读(1380) 评论(0) 编辑 收藏 举报