1、包
-
什么是包?
包是组织类的一种形式
-
为什么要用包?
保证类的唯一性,使得类名可以重复
-
常规导包
a、import关键字
导包可以导入特定的类名,也可以用通配符,如
import java.sql.Date;//特定 import java.util.*;//通配符
b、注意事项
-
在java中使用通配符并不是导入包下所有的类,而是在本类中用到了哪个类就导入哪个类
-
虽然通配符很方便,但可能会发生冲突,如下
import java.util.*; import java.sql.*; ... Date date = new Date(); // 编译出错Error:对Date的引用不明确; //这是因为 java.sql 包下和 java.util 包下都有 Date 这个类,编译器不知道导入哪个Date类
这上述这种情况下,就要用完整类名import java.util.Date;
-
java.lang包下的类是自动导入,但是lang包下嵌套的包中的类要手动导入
-
import java .* ; 这是不允许的,因为在java语言中规定,这里的*只代表某些类的名字。
c、常见系统包
- java.lang:系统常用基础类 (String、Object)
- java.lang.reflflect:java 反射编程包
- java.net:进行网络编程开发包
- java.sql:进行数据库开发的支持包
- java.util:是java提供的工具程序包
- java.io:I/O编程开发包
-
-
静态导入
import static用于导入指定类的某个静态成员变量、方法或全部的静态成员变量、方法。
-
包的访问控制权限
private default protected public 本类 √ √ √ √ 同包 × √ √ √ 异包子类 × × √ √ 异包非子类 × × × √
2、继承
-
面向对象的基本特征?
封装继承多态
-
继承的作用?
继承是对共性的抽取,主要是为了代码重用,体现在代码上就是使用extends关键字实现继承。此外,也正是因为有了继承,才有方法覆盖和多态机制
-
什么时候可以继承?
满足" is a "关系
比如 “cat is a animal” , " dog is a animal ",这种情况下cat和dog就可以继承Animal
继承时,cat/dog被称为子类,派生类,Animal被称为父类、基类或超类
所有类默认继承Object类(老祖宗类)
-
语法规则?
-
java中只支持单继承,但支持实现多接口
-
对于父类中的私有字段和方法,子类可以继承,但是无法访问,可以通过get、set访问父类中的私有属性
-
子类会继承父类的所有 public 的字段和方法,protected和default会视情况继承(包含类方法)
-
构造方法不会继承
-
子类继承父类,必须帮助父类先构造
构造器的执行顺序是从根部的基类开始,一直到距离本类最近的父类,最后执行本类的构造器
class A { public A() {} } class B extends A { public B() {} } class C extends C { public C() {} } C c = new C(); //实例化C对象,依次调用的顺序是A()->B()->C()方法
也就是实例化子对象,会先调用父类型的构造方法初始化父类的那部分特征。
-
对于静态变量,在子类中修改会影响到父类
-
-
final关键字
-
final修饰的类不能被继承,叫密封类
-
final修饰的方法无法覆盖
-
final修饰的变量只能赋一次值
-
final修饰的引用一旦指向某个对象,则不能再重新指向其它对象,但该引用指向的对象内部的数据是可以修改的
-
final修饰的实例变量必须手动初始化,不能采用系统默认值
-
final修饰的实例变量一般和static联合使用,称为常量
public static final double PI = 3.1415926;
-
-
super关键字?
6.1、super能出现在实例方法和构造方法中
6.2、super的语法是:“super.”、“super()”
6.3、super不能使用在静态方法中。
6.4、super . 大部分情况下是可以省略的。那么super .什么时候不能省略呢?
父类和子类中有同名属性,或者说有同样的方法,想在子类中访问父类的,super . 不能省略。6.5、super的使用:
super.属性名 //【访问父类的属性】 super.方法名(实参) //【访问父类的方法】 super(实参) //【调用父类的构造方法】
6.6、super在内存图中体现:
可以看出,在多级继承中,super只会指向最近的基类 -
super和this的区别?
super的使用基本与this一致,主要区别在于
- super代表父类对象的引用
- this代表本类对象的引用
- super虽然代表子类的父类对象,但是不持有父类对象的地址值,而this作为当前子类对象
- this()和super()都只能在构造方法的第一行
- super和this都市依赖当前对象的,不能用在static方法中
-
java实现多继承的三种方式
- 内部类
- 实现接口
- 一个父类继承另一个父类
protected修饰的属性a,对于不同包的子类中,只能通过super访问a,不能通过当前对象访问a,
子类和父类中的字段同名时,也符合就近原则,要想访问父类中的那个同名字段,必须使用super
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
public Cat() {
}//报错
},
3、多态
-
何为多态?
多种形态,多种状态,编译和运行有两个不同的状态。
编译期叫做静态绑定。
运行期叫做动态绑定。class Animal { public void move(){} } class Cat extends Animal { } Animal a = new Cat(); a.move();
编译时,编译器发现a的类型时Animal,所以编译器会去Animal类中找move()方法,找到了,静态绑定,编译通过(这也就是为什么如果访问子类特有的方法时会报错,因为静态绑定出错)
运行的时候和底层堆内存当中的实际对象有关,真正执行时会自动调用"堆内存中真实对象"的相关方法,也就是会调用Cat类中的move()方法 -
向上转型指什么?
把子类型对象直接赋给父类型引用,如第一条中所演示的:
Animal a = new Cat();
-
向上转型发生的时机?
-
直接赋值(同2)
-
方法传参
public static void doSome(Animal animal){ } Animal.doSome(new Cat())
-
方法的返回值
public static Animal func() { return new Cat(); }
-
-
向下转型指什么?
通过父类引用调用方法或成员变量时,只能调用父类中已有的方法和字段,要想访问子类中特有的方法和字段,只能向下转型
class A { public void doSome(){} } class B extends A{ //子类继承了父类的doSome() public void doOther(){}//子类特有的方法 } public static void main(String[] args) { A a = new B(); a.doSome();// √ a.doOther();//Cannot resolve method 'doOther' in 'A' //这时候只能向下转型 B b = (B)a; b.doOther();// √ }
向下转型注意什么?
最好使用instanceof判断一些,以防出现ClassCastException
上面代码合适的做法是:
if(a instanceof B) { B b = (B)a; } //"如果a这个引用指向的对象时B类型,就向下转型,否则不执行"
-
重写(override,方法覆盖)
a、怎么在代码级别上构成方法覆盖?
- 两个类要有继承关系
- 重写之后的方法和之前的方法具有相同的返回值类型、方法名、形式参数列表
b、注意事项?
- 访问权限不能更低,可以更高
- 不能被final修饰,被final修饰的方法是密封方法,不能被重写
- 重写之后的方法不能比之前的方法抛出更多的异常
- 父类不能被private修饰
- 方法不能是static修饰的
-
和重载(overload)的区别?
a、重载条件?
-
在同一个类中,方法名相同,参数列表不同
-
参数列表不同指
参数个数不同
参数顺序不同
参数类型不同
-
对返回值类型和修饰符列表无要求
-
注意:重载不是只能发生在同一个类中
lf two methods of a lass (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the samename but signatures that are not override-equivalent, then the method name is said to be overloaded. --The Java® Language Specification
如果一个类的两个方法(无论是在同一个类中声明的,还是由一个类继承的,还是一个声明后继承的)具有相同的名称,但不具有覆盖等效的sianatures,则该方法名被称为重载。
从Oracle官方文档可以看出,在一个子类中也是可以发生重载的:只要具有相同的方法名,但又不构成覆盖,就是重载。
b、我们可以用一张图来区分重载和重写的区别:
【图片来源于网络,侵权必删】
重写是因为父类的方法不满足子类的业务需求,在父类的基础上进行扩写,而重载是一类功能相似的方法,为了方便代码编写而把方法名定为相同
-
-
构造方法中也能发生动态绑定
class A { public A() { func(); } public void func() { System.out.println("A的func"); } } class B extends A { int num = 10; @Override public void func() { //super();隐式调用 System.out.println("B的func " + num); } } public class Test() { public static void main(String[] args) { A a = new B(); } } //结果: B的func 0
构造 B 对象的时候, 会先调用 A 的构造方法.A的构造方法调用了func方法,此时会触发动态绑定,执行堆内存中"真实对象"的func方法,也就是B类中重写的func方法。此时B对象还未完成构造,故num处在未初始化状态,值为0,故最终输出结果是:“B的func 0”
4、抽象类
-
抽象方法没有方法体
问:没有方法体的方法都是抽象方法?
错;native方法也没有方法体
public native int hashCode();
这个方法底层调用了C++写的动态链接库程序。前面修饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。 -
抽象类中可以包含其他的非抽象方法(成员方法和类方法都可),也可以包含字段(静态或实例变量). 非抽象方法可以被重写,也可以被子类直接调用
-
抽象类不能实例化
问:抽象类不能实例化,为什么要包含非抽象方法和构造方法?
是用来给子类使用的
-
一个非抽象类继承了抽象类,那么这个类必须重写所有的抽象方法
-
abstract和final是对立的
因为abstract修饰的类或方法就是为了继承和重写,而final修饰的类不能被继承,修饰的方法不能被重写
-
抽象类B可以继承抽象类A,当非抽象类C继承A类时,必须重写A和B类中所有的抽象方法
-
抽象方法不能被private修饰,且不能出现在非抽象类中
abstract private void draw(); // 编译出错 //Error:(4, 27) java: 非法的修饰符组合: abstract和private
-
抽象类也能发生向上、向下转型,即满足多态
5、接口
-
概念
Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)
在我看来,接口就是一种特殊的类,相比于抽象类中还可以包含非抽象方法,字段,在接口中只能包含静态常量和抽象方法(JDK7以前)
-
接口中的方法默认被 public abstract修饰,因此可以省略
-
接口中的字段默认被 public static final修饰,也可以省略
-
阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性,如下:
public abstract void doSome(); void doSome(); public static final String NATION=“China”; String NATION=“China”; 完整格式 简化格式(推荐) -
在JDK8以后,接口中可以定义普通方法,但要被"default"修饰,称为默认方法,可以被重写
-
各个版本对比
版本 内容 JDK 7及以前 成员常量、抽象方法 JDK 8 默认方法、静态方法 JDK 9及以后 私有方法 注意:"内容"指新增加的,新版本包含以前版本的内容
-
接口不能实例化
-
实现多个接口和继承类在代码层次怎么写?
public class Test extends A implements B, c { }
-
接口中的静态方法不能被实现类使用,也不能被实现类的实例对象调用,只能用Interface.方法名()。相比之下,
普通类继承父类,可以用子类类名和子类实例对象调用父类中的静态方法,只不过后者不建议使用
-
接口和接口之间的关系
接口和接口之间是继承,实现了接口扩展其他接口的功能
可以看到,在java源码中,两个接口之间使用的是"extends"关键字进行维护的
-
接口也能发生向上、向下转型,即接口也支持多态
-
接口一般以大写 "I"开头,如 " IFly "