第一章 final关键字
1. final关键字基本语法
- final修饰的类无法继承。
- final修饰的方法无法覆盖。
- final修饰的变量只能赋一次值。
- final修饰的引用一旦指向某个对象,则不能再重新指向其它对象,但该引用指向的对象内部的数据是可以修改
- final修饰的实例变量必须手动初始化,不能采用系统默认值。
- final修饰的实例变量一般和static联合使用,称为常量,例如:public static final double PI = 3.1415926;
第二章 抽象类
1. 抽象类概念
1.1 什么是抽象类
类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类。类本身是不存在的,所以抽象类无法创建对象(无法实例化)。
类到对象是实例化。对象到类是抽象。
1.2 抽象类怎么定义
[修饰符列表] abstract class 类名{
类体;
}
2. 抽象类基础语法
- 抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的。
- final和abstract不能联合使用,这两个关键字是对立的。(final修饰的不可以被其它类继承,而abstract修饰的是用来被子类继承的)
- 抽象类的子类可以是抽象类。也可以是非抽象类;抽象类是可以继承实体类,但前提是实体类必须有明确的构造函数 ```java //1.所有的class都必须有一个构造方法,如果你没有在代码里声明构造方法, //系统会自动给你生成一个公有无参的构造方法。而只要你自己声明了一个构造方法, //无论有参无参,私有公有,系统就不再帮你生成默认无参构造器了。 //2.所有的子类构造器都要求在第一行代码中调用父类构造器,如果不写,系统默认去调用父类的无参构造器。 //所以,如果把系统默认配给的方法也算进去,class A{}的代码实际上是
class A{
public A(){}
}
B继承 A 的时候,则是
abstract class B extends A{
public B(){
super();
}
}
//要试验出这继承规则的内部情况,也很简单,在最上面那个简单试验代码里,加上个私有构造器,有参无参都行。
class A{
private A(){}
}
- 抽象类虽然无法实例化,但是**抽象类有构造方法,这个构造方法是供子类使用的**。
- 抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中;即当抽象方法的子类为非抽象类时,需要将父类的抽象方法实现(覆盖)
> 抽象方法表示没有实现的方法(没有方法体的方法)例如:
> public abstract void doSome();
> 抽象方法特点是:
> 特点1:没有方法体,以分号结尾
> 特点2:前面修饰符列表中有abstract关键字
<a name="wb4q2"></a>
# 第三章 接口
<a name="1wza3"></a>
## 1. 接口的基本语法
<a name="4J9jU"></a>
### 1.1 接口基本知识
1、接口也是一种“引用数据类型”。编译之后也是一个class字节码文件。
2、接口是完全抽象的。(抽象类是半抽象。)或者也可以说接口是特殊的抽象类。
3、接口怎么定义,语法是什么?<br />[修饰符列表] interface 接口名{}
4、接口支持多继承,一个接口可以继承多个接口。
5、接口中只包含两部分内容:<br />一部分是:常量(public static final可以省略),一部分是:抽象方法;接口中没有其它内容了。只有以上两部分。
6、接口中所有的元素都是public修饰的。(都是公开的。)
7、接口中的抽象方法定义时:public abstract修饰符可以省略。
8、接口中的方法都是抽象方法,所以接口中的方法不能有方法体。
9、接口中的常量的public static final可以省略。
<a name="bctL1"></a>
### 1.2 接口基本语法
- 类和类之间叫做继承,类和接口之间叫做实现(implements)。
- 当一个非抽象的类实现接口的话,必须将接口中所有的抽象方法全部实现(覆盖、重写)。
- 一个类可以同时实现多个接口。(对于计算机来说,一个机箱上有多个接口,一个接口是接键盘的,一个接口是接鼠标的)
- 接口A和接口B虽然没有继承关系,但是写代码的时候,可以互转;编译器没意见,但是运行时可能出现:ClassCastException。
> 之前有一个结论:无论向上转型还是向下转型,两种类型之间必须要有继承关系,没有继承关系编译器会报错。(这句话不适用在接口方面。)最终实际上和之前还是一样,需要加:instanceof运算符进行判断。向下转型养成好习惯。转型之前先if+instanceof进行判断。
```java
public class Test03{
public static void main(String[] args){
// 多态该怎么用呢?
// 都是父类型引用指向子类型对象
A a = new D();
//a.m2(); // 编译报错。A接口中没有m2()方法。
B b = new D();
C c = new D();
// 这个编译没问题,运行也没问题。
// 调用其他接口中的方法,你需要转型(接口转型。)
B b2 = (B)a;
b2.m2();
// 直接向下转型为D可以吗?可以
D d = (D)a;
d.m2();
M m = new E();
// 经过测试:接口和接口之间在进行强制类型转换的时候,没有继承关系,也可以强转。
// 但是一定要注意,运行时可能会出现ClassCastException异常。
// 编译没问题,运行有问题。
//K k = (K)m;
if(m instanceof K){
K k = (K)m;
}
}
}
interface K{
}
interface M{
}
class E implements M{
}
// --------------------------------------------------------------------
interface X{
}
interface Y{
}
interface Z extends X,Y{ //接口和接口支持多继承。
}
//------------------------------------------------------------------
interface A{
void m1();
}
interface B{
void m2();
}
interface C{
void m3();
}
// 实现多个接口,其实就类似于多继承。
class D implements A,B,C{
// 实现A接口的m1()
public void m1(){
}
// 实现B接口中的m2()
public void m2(){
System.out.println("m2 ....");
}
// 实现接口C中的m3()
public void m3(){
}
}
1.3 继承和实现都存在的话,代码应该怎么写
/*
继承和实现都存在的话,代码应该怎么写?
extends 关键字在前。
implements 关键字在后。
*/
public class Test04{
public static void main(String[] args){
// 创建对象(表面看Animal类没起作用!)
Flyable f = new Cat(); //多态。
f.fly();
// 同一个接口
Flyable f2 = new Pig();
// 调用同一个fly()方法,最后的执行效果不同。
f2.fly();
Flyable f3 = new Fish();
f3.fly();
}
}
// 动物类:父类
class Animal{
}
// 可飞翔的接口(是一对翅膀)
// 能插拔的就是接口。(没有接口你怎么插拔。)
// 内存条插到主板上,他们之间有接口。内存条可以更换。
// 接口通常提取的是行为动作。
interface Flyable{
void fly();
}
// 动物类子类:猫类
// Flyable是一个接口,是一对翅膀的接口,通过接口插到猫身上,让猫变的可以飞翔。
class Cat extends Animal implements Flyable{
public void fly(){
System.out.println("飞猫起飞,翱翔太空的一只猫,很神奇,我想做一只猫!!");
}
}
// 蛇类,如果你不想让它飞,可以不实现Flyable接口
// 没有实现这个接口表示你没有翅膀,没有给你插翅膀,你肯定不能飞。
class Snake extends Animal{
}
// 想飞就插翅膀这个接口。
class Pig extends Animal implements Flyable{
public void fly(){
System.out.println("我是一只会飞的猪!!!");
}
}
// 鱼(默认实际上是存在继承的,默认继承Object。)
/*
class Fish extends Object implements Flyable{
}
*/
class Fish implements Flyable{ //没写extends,也是有的,默认继承Object。
public void fly(){
System.out.println("我是六眼飞鱼(流言蜚语)!!!");
}
}
2. 接口在开发中的作用
- 接口在开发中的作用,类似于多态在开发中的作用。
- 面向接口编程,可以降低程序的耦合度,提高程序的扩展力,符合OCP开发原则;接口的使用离不开多态机制。(接口+多态才可以达到降低耦合度)
3. 类型和类型之间的关系
is a(继承)、has a(关联)、like a(实现)
is a:
Cat is a Animal(猫是一个动物)<br /> 凡是能够满足is a的表示“继承关系” <br /> b. has a:<br /> I has a Pen(我有一支笔)<br /> 凡是能够满足has a关系的表示“关联关系”<br /> 关联关系通常以“属性”的形式存在。<br /> c. like a:<br /> Cooker like a FoodMenu(厨师像一个菜单一样)<br /> 凡是能够满足like a关系的表示“实现关系”<br /> 实现关系通常是:类实现接口。
4. 抽象类和接口的区别
在这里我们只说一下抽象类和接口在语法上的区别(至于以后抽象类和接口应该怎么进行选择,通过后面的项目去体会)
抽象类是半抽象的。<br /> 接口是完全抽象的。
抽象类中有构造方法。<br /> 接口中没有构造方法。
** 接口和接口之间支持多继承。**<br /> 类和类之间只能单继承。
一个类可以同时实现多个接口。<br /> 一个抽象类只能继承一个类(单继承)。<br /> **接口中只允许出现常量和抽象方法**。
第四章 包
1. package概述及使用
1.1 package概述
package是java中包机制。包机制的作用是为了方便程序的管理。不同功能的类分别存放在不同的包下。
1.2 package怎么用
package是一个关键字,后面加包名。例如:package com.bjpowernode.javase.chapter17;
注意:package语句只允许出现在java源代码的第一行。
1.3 包名的命名规范
一般都采用公司域名倒序的方式(因为公司域名具有全球唯一性。)包名命名规范:公司域名倒序 + 项目名 + 模块名 + 功能名
1.4 对于带有package的java程序编译、运行
编译:
javac -d . HelloWorld.java
解释一下:
javac 负责编译的命令
-d 带包编译
. 代表编译之后生成的东西放到当前目录下(点代表当前目录)
HelloWorld.java 被编译的java文件名。
运行:
java com.bjpowernode.javase.chapter17.HelloWorld
2. import
2.1 import使用
- import 完整类名;
- import 包名.*;
- import语句只能出现在package语句之下,class声明语句之上。
import java.util.Scanner;和import java.util.; 这样是不是效率比较低。 // 这个效率不低,因为编译器在编译的时候,会自动把变成具体的类名。 import java.util.; // 想省懒劲你不能太省了。 import java.; 这是不允许的,因为在java语言中规定,这里的*只代表某些类的名字。
2.2 import什么时候不需要
- java.lang不需要
- 同包下不需要
第五章 访问控制权限
1. 访问控制权限基本概念
1.1 访问控制权限都有哪些
private 私有
public 公开
protected 受保护
默认
默认不写不是说在前面加上default
1.2 控制的范围
访问控制修饰符 | 本类 | 同包 | 子类 | 任意位置 |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
默认 | 可以 | 可以 | 不可以 | 不可以 |
private | 可以 | 不可以 | 不可以 | 不可以 |
范围从大到小排序:public > protected > 默认 > private
1.3 访问控制权限修饰符可以修饰什么
属性(4个都能用)
方法(4个都能用)
类(public和默认能用,其它不行。)
接口(public和默认能用,其它不行。)
第六章 object类中的一些方法
本章需要了解学习的方法: protected Object clone() // 负责对象克隆的。
int hashCode() // 获取对象哈希值的一个方法。 boolean equals(Object obj) // 判断两个对象是否相等 String toString() // 将对象转换成字符串形式 protected void finalize() // 垃圾回收器负责调用的方法
1. toString()方法
1.1 如何学习这些方法
- 第一种方法:去源代码当中。(但是这种方式比较麻烦,源代码也比较难)
- 第二种方法:去查阅java的类库的帮助文档。
什么是API? 应用程序编程接口。(Application Program Interface) 整个JDK的类库就是一个javase的API。 每一个API都会配置一套API帮助文档。 SUN公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)
1.2 tostring方法学习
1、源代码长什么样?
public String toString() {
//源代码上toString()方法的默认实现是:
//类名@对象的内存地址转换为十六进制的形式
return this.getClass().getName() + "@" + Integer.toHexString(hashCode());
}
2、SUN公司设计toString()方法的目的<br /> 通过调用这个方法可以将一个“java对象”转换成“字符串表示形式”
3、其实SUN公司开发java语言的时候,建议所有的子类都去重写toString()方法;toString()方法应该是 一个简洁的、详实的、易阅读的。
2. equals方法
1、equals方法的源代码
public boolean equals(Object obj) {
//this代表的是当前调用方法的对象,如在主方法创建该类对象,并赋给a引用,
//那么a.equals(obj);便是a == obj;
return (this == obj);
}
2、SUN公司设计equals方法的目的是什么?
以后编程的过程当中,都要通过equals方法来判断两个对象是否相等;equals方法是判断两个对象是否相等的。
3、我们需要研究一下Object类给的这个默认的equals方法够不够用!!!!
在Object类中的equals方法当中,默认采用的是“==”判断两个java对象是否相等。而“==”判断的是两个java对象的内存地址,我们应该判断两个java对象的内容是否相等。所以老祖宗的equals方法不够用,需要子类重写equals。
4、判断两个java对象是否相等,不能使用“==”,因为“==”比较的是两个对象的内存地址。
String类重写toString、equals方法
5、重写equals方法
// 示例:
// 重写规则:当一个用户的用户名和家庭住址都相同,表示同一个用户。
// 这个equals判断的是User对象和User对象是否相等。
public boolean equals(Object obj){
// 用户名和用户名相同,住址和住址相同的时候,认定是同一个用户。
//下面这几行代码可以当作一个模板
if(obj == null || !(obj instanceof User)) return false;
if(this == obj) return true;
User u = (User)obj;
if(this.name.equals(u.name) && this.addr.equals(u.addr)){
return true;
}
return false;
}
6、还需注意重写equals方法要彻底
3. finalize()方法
1、在Object类中的源代码:
// GC:负责调用finalize()方法。
protected void finalize() throws Throwable { }
2、finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的。
3、这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法
不同于equals、toString,equals和toString()方法是需要你写代码调用的;finalize()只需要重写,重写完将来自动会有程序来调用。
4、finalize()方法的执行时机:
当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法。
5、finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机;
如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中。
提示:
java中的垃圾回收器不是轻易启动的,垃圾太少,或者时间没到,种种条件下, 有可能启动,也有可能不启动。 有一段代码可以建议垃圾回收器启动。 System.gc(); // 建议启动垃圾回收器。(只是建议,可能不启动,也可能启动。启动的概率高了一些。)
4. hashCode方法
1、在Object类中的源代码:
public native int hashCode();
2、hashCode()方法返回的是哈希码:
实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值;所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址。