final是Java语言中的一个关键字,表示最终的,不可变得。final可以修饰变量以及方法还有类等。
final修饰的类不能被继承,修饰的方法不能被重写与覆盖,修饰的变量只能赋值一次。
1.1 final修饰引用问题package com.zh0u.final关键字;
public class FinalTest02 {
public static void main(String[] args) {
Person p1 = new Person(20);
System.out.println(p1.age); // 20
p1.age = 100;
System.out.println(p1.age); // 100
final Person person = new Person(30);
person.age = 70;
System.out.println(person.age); // 70
}
}
class Person{
int age;
public Person(){}
public Person(int age){
this.age = age;
}
}
1.2 final修饰引用问题
==实例变量如果没有手动赋值,系统会赋默认值。final修饰的实例变量,系统不会赋默认值,要求程序员必须手动赋值。==这个手动赋值,在变量后面直接赋值可以,在构造方法中赋值也可以。
实例变量在对象被new的时候才会赋初始值。
package com.zh0u.final关键字;
public class FinalTest03 {
}
class User{
// 实例变量
// 编译器报错
// final int age;
// 实例变量
final double height = 1.8;
// 以下这堆代码全部联合起来,weight变量也只是赋值了1次。
// 实例变量
final double weight = 0;
// 构造方法
public User(){
// 如果这里不写这行代码,系统会默认执行this.weight = 0;这样会报错。
// 只要赶在系统赋默认值之前赋值就可以。
// this.weight = 80;
}
}
1.3 常量
final修饰的实例变量一般添加static修饰,final加static联合修饰的变量成为常量,一般常量变量名全部采用大写,中间使用下划线连接。
常量:实际上常量和静态变量一样,区别在于:“常量的值不能变”,都是存储在方法区,并且都是在类加载是初始化。
常量一般都是公开的。
package com.zh0u.final关键字;
public class FinalTest04 {
public static void main(String[] args) {
System.out.println(Chinese.COUNTRY);
// 常量是无法重新赋值的。
// Chinese.COUNTRY = "美国";
}
}
class Chinese{
// 身份证号,每个人都不一样,对象级别的。
String idCard;
// 姓名,对象不同姓名就不同。
String name;
// 国家的值是一个固定值:“中国”
// 实例变量在堆中,一个对象一份。100个对象100份。
// 实例变量既然使用final修饰了,说明该实例变量值不会随着对象的变化而变化。
// 该实例变量前面应该添加:static关键字,变为静态的,存储在方法区。
// final String country = "中国";
final static String COUNTRY = "中国";
}
1.5 总结
- final修饰的类无法继承。
- final修饰的方法无法覆盖。
- final修饰的变量只能赋值一次。
- final修饰的引用一旦指向某个对象,则不能在重新指向其它对象,但该引用指向的对象内部的数据是可以修改的。
- final修饰的实例变量必须手动初始化,不能采用系统默认值。
- final修饰的实例变量一般和static联合使用,成为常量。
类到对象是实例化,对象到类是抽象。
2.1 什么是抽象类类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类,类本身是不存在的,所有抽象类无法创建对象《无法实例化》,所以抽象类是用来被子类继承的,抽象类的子类还可以为抽象类。
抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的(子类在继承的时候会默认调用super()方法来调用父类的构造方法),抽象类的子类既可以是非抽象类也可以是抽象类。
final不能与关键字abstract一起修饰一个类。
抽象类也属于引用数据类型,定义的语法如下:
[修饰符列表] abstract class 类名{
类体;
}
2.2 抽象方法
抽象类关联到一个概念:抽象方法,什么是抽象方法?抽象方法表示没有实现(没有方法体)的方法,如:
public abstract void doSome();
抽象方法的特点:
- 没有方法体也没有花括号,以分号结尾。
- 前面修饰符类表中有abstract关键字。
抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中。
package com.zh0u.抽象类;
public class AbstractTest01 {
public static void main(String[] args) {
// 抽象类不能被继承
// new Account();
// 思考:以下程序能不能使用多态?答案:能
// 以下的代码就是面向抽象编程思想。
Account account = new CreditAccount(); // 向上转型,父引用指向子类对象。
account.doSome(); // 信用卡取款中......
}
}
abstract class Account{
public Account(){} // 这个构造方法由系统系统自动提供,用来供子类使用。
Account(String name){}
public abstract void doSome(); // 抽象类中定义了抽象方法,则子类必须对这个抽象方法进行继承。
}
// 非抽象类继承抽象类,必须将父类中的继承过来的抽象类进行重写或实现。
// 原因是子类从父类(抽象类)中继承过来抽象方法只能出现在抽象类中,但是子类不是,所以只能重写。
class CreditAccount extends Account{
public CreditAccount(){
super();
}
// 子类重写父类(抽象类)中的方法
public void doSome(){
System.out.println("信用卡取款中......");
}
}
// 当然如果子类也是抽象类,那么也可以不去重写父类中的抽象方法。原因是子类继承过来的抽象方法doSome()也是在抽象方法AgriculturalAccount类中。
abstract class AgriculturalAccount extends Account{
}
面试题(判断题):Java语言汇总凡是没有方法体的方法都是抽象方法?
不对,错误的。
Object类中就有很多方法都没有方法体,都是以“;”号结尾,但它们度不是抽象方法,如:
public native int hashCode();
这个方法底层调用了C++写的动态链接库程序,前面的修饰符列表中没有“abstract”,有一个native,表示调用JVM本地程序。
3、接口接口也是一种引用数据类型,编译之后也会生成一个class字节码文件。接口是完全抽象的或也可以说接口是特殊的抽象类。
3.1 接口的基础语法接口的定义:
[修饰符列表] interface 接口名{}
接口支持继承和多继承,即一个接口可以继承多个接口,多个接口之间使用“,”分隔开即可。
interface A{}
interface B{}
interface C extends A, B{
}
接口中只包含两部分内容,一部分是:常量(值不能改变),另一部分是:抽象方法。
接口中所有的元素都是public修饰的。
接口中的抽象方法定义时:public abstract 修饰符可以省略,编译器编译的时候会自动加上。
接口中的方法都是抽象方法,所有接口中的方法不能有方法体。
类通过implements关键字来对接口的方法进行实现(继承),通过implements实现(继承)的类,必须重写对应接口中的所有抽象方法。
总结
- 接口是一种“引用数据类型”。
- 接口是完全抽象的。
- 接口怎么定义:[修饰符列表] interface 接口名{}
- 接口支持多继承
- 接口中只有常量+抽象方法
- 接口中所有的元素都是public修饰的
- 接口中抽象方法的public abstract可以省略。
- 接口中常量的public static final可以省略。
- 接口中方法不能有方法体。
- 一个非抽象的类,实现接口的时候,必须将接口中所有的方法加以实现。
- 一个类可以实现多个接口。
- extends和implements可以共存,extends在前,implements在后。
- 使用接口,写代码的时候,可以使用多态(父类型引用指向子类型对象)。
类和类之间叫做继承,类和接口之间叫做“实现”,这里的实现也可以理解为“继承”。
package com.zh0u.接口;
public class InterfaceTest02 {
public static void main(String[] args) {
// 访问接口常量
System.out.println(MyMath.PI); // 3.1415936
// 注意接口是无法实例化的,以下代码编译器在编译是会报错
// new MyMath();
// 核心思想: 面向接口编程(核心还是多态)
MyMath myMath = new MyMathImpl();
System.out.println(myMath.sub(20, 10));
System.out.println(myMath.sum(20, 10));
}
}
interface MyMath{
// 常量 public static final 可以省略
public static final double PI = 3.1415936;
// 抽象方法,public abstract 可以省略
public abstract int sum(int a, int b);
// 接口中的方法不能有方法体,以下代码会编译器会报错。
// void doSome(){}
// 相减的抽象方法
int sub(int a, int b);
}
class MyMathImpl implements MyMath{ // 类通过implements来实现接口中的方法
@Override
public int sum(int a, int b) { // 这里的public不能省略
return a + b;
}
@Override
public int sub(int a, int b) {
return a - b;
}
}
接口和接口之间支持多继承,那么一个类可以同时实现多个接口吗?答案:可以。
interface W{
public abstract int m1();
}
interface Y{
public abstract int m2();
}
interface Z{
public abstract int m3();
}
class t implements W, Y, Z{
@Override
public int m1() {
return 0;
}
@Override
public int m2() {
return 0;
}
@Override
public int m3() {
return 0;
}
}
3.3 继承和实现连用
extends和implements可以共存,extends在前,implements在后。
public class InterfaceTest04 {
public static void main(String[] args) {
// 面向接口编程 ---多态----
Flyable cat = new Cat();
cat.fly(); // 飞猫起飞,翱翔太空的一只猫!!!
Flyable pig = new Pig();
pig.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("我是一直会飞的飞猪!!!");
}
}
// 这里没有写 extends关键字,但是Fish默认还是要继承Object类
class Fish implements Flyable{
@Override
public void fly() {
System.out.println("我是六眼飞鱼(流言蜚语)!!!");
}
}
3.4 接口在开发中的作用
接口在开发中的作用,类似于多态在开发中的作用。
**多态:**面向抽象编程,不行面向具体编程。降低程序的耦合度,提供程序的扩展力(OCP)原则。
接口的作用?
接口是完全抽象的,而我们以后正好要求面向抽象编程。面向抽象编程这句话可以修改为:“面向接口编程”。接口的扩展性好,可插拔,符合OCP开发原则。
接口的使用离不开多态机制(接口+多态才可以达到降低耦合度)。
以后进行大项目开发,一般都是讲项目分离成一个模块一个模块的,各模块之间采用接口衔接。降低耦合度。
FoodMenu.java
package com.zh0u.接口在开发中的作用;
public interface FoodMenu {
// 西红柿炒蛋
void shiZiChaoJiDan();
// 鱼香肉丝
void yuXiangRouSi();
}
ChineseCooker.java
package com.zh0u.接口在开发中的作用;
public class ChineseCooker implements FoodMenu{
@Override
public void shiZiChaoJiDan() {
System.out.println("中国厨师做的西红柿炒蛋!!!");
}
@Override
public void yuXiangRouSi() {
System.out.println("中国厨师做的鱼香肉丝!!!");
}
}
WesternCooker.java
package com.zh0u.接口在开发中的作用;
public class WesternCooker implements FoodMenu{
@Override
public void shiZiChaoJiDan() {
System.out.println("西方厨师做的西红柿炒蛋!!!");
}
@Override
public void yuXiangRouSi() {
System.out.println("西方厨师做的鱼香肉丝!!!");
}
}
Customer.java
package com.zh0u.接口在开发中的作用;
// 顾客
public class Customer {
// 顾客手里有一个菜单
// Customer has a FoodMenu! 重点:has a
// 重点:以后凡是能够使用 has a 来描述的,统一以属性的方式存在。
// 实例变量,属性
private FoodMenu foodMenu; // 面向接口编程(抽象编程)可以降低程序的耦合度,提高程序的扩展力。
// 如果以下这样写,就表示写死了(焊接了,没有课插拔了)
// 中餐厨师
// ChineseCooker chineseCooker;
// 西餐厨师
// WesternCooker westernCooker;
// 构造方法
public Customer(){}
public Customer(FoodMenu foodMenu){this.foodMenu = foodMenu;}
// setter and getter
public FoodMenu getFoodMenu() {
return foodMenu;
}
public void setFoodMenu(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
// 顾客点菜的方法
public void order(){
this.foodMenu.yuXiangRouSi();
this.foodMenu.shiZiChaoJiDan();
}
}
Test.java
package com.zh0u.接口在开发中的作用;public class Test { public static void main(String[] args) { // 创建厨师对象 FoodMenu chineseCooker = new ChineseCooker(); // 创建顾客对象 Customer customer = new Customer(chineseCooker); // 顾客点菜 customer.order(); }}
3.5 类型之间的关系(理解)
is a、has a、like a
is a:
Cat is a Animal(猫是一个动物),凡是能够满足is a的表示“继承关系”。
has a:
I has a Pen(我有一只笔),凡是能够满足has a关系的表示“关联关系”,关联关系通常以“属性”的形式存在。
like a:
Cooker like a FoodMenu(厨师像一个菜单一样),凡是能够满足like a关系的表示“实现关系”,实现关系通常是:类实现接口。
4、抽象类与接口的区别这里只说一下抽象类和接口在语法上的区别,至于以后抽象类和几口应该怎么进行选择,通过项目区学习。
- 抽象类是半抽象的,接口是完全抽象的。
- 抽象类中有构造方法,接口中没有构造方法。
- 接口和接口之间支持多继承,类和类之间只能单继承。
- 一个类可以同时实现多个接口,一个抽象类只能继承一个类。
- 接口中只允许出现常量和抽象方法。
- 一般抽象类使用的还是少,接口一般都是对“行为”的抽象。
JDK类库的根类 — Object
先研究一下Object,因为这些方法都是所有子类通用的,任何一个类默认继承Object。就算没有直接继承,最终也会间接继承。
Object类当中的那些常用方法,我们可以到哪里去找?
第一种:去源代码中(不推荐,难度较大)。
第二种:去查阅java类库的帮助文档。
目前为止我们只需要知道这几个方法即可:
protected Object clone() 对象克隆 boolean equals(Object obj) 判断两个对象是否相等 int hashCode() 获取对象哈希值的一个方法 protected void finalize() 垃圾回收器负责调用的方法 String toString() 将对象转换为字符串形式5.1 toString方法
源代码
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
源代码上toString()方法的默认实现是:类名@对象的内存地址转换为十六进制的形式。
toString的作用是通过调用这个方法可以将一个“Java对象”转换成“字符串”的形式输出。
SUN公司开发Java语言的时候,建议所有的子类都去重写toString()方法,toString()方法应该是一个简洁的、详实的、容易阅读的。
注意:Java在输出引用的时候,如果不调用toString()方法,也会默认调用它。
package com.zh0u.Object类;
public class Object_toString {
public static void main(String[] args) {
System.out.println(new definedDate(1970, 1, 1)); // 直接输出引用,默认也会调用 toString() 方法
}
}
class definedDate{
int year, month, day;
public definedDate(){}
public definedDate(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
@Override
public String toString() { // 重新父类中的 toString() 方法
return "definedDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}
5.2 equals方法
源代码:
public boolean equals(Object obj) {
return (this == obj);
}
这个方法是Object类默认实现的,判断两个java对象是否相等,不能使用“ == ” ,因为“==
补充:什么是API?应用程序编程接口,整个JDK的类库就是一个javase的API,每个API都会配置一套API帮助文档。
6、package和import 6.1 关于Java语言的package和import机制:- 为什么使用package?
package是java中包机制。包机制的作用是为了方便程序的管理。不同功能的类分别存在在不同的包下(按照功能划分,不同软件包具有不同的功能)。
- package的怎么用?
package是一个关键字,后面加包名,例如:package com.zh0u.javase.interfacetest;
注意:package语句只允许出现在java源代码的第一行。
- 包名命名规范?
一般都采用公司域名倒序的方式(因为公司域名具有唯一性)。命名规范为:
公司域名倒序 + 项目名 + 模块名… [ + 功能名 ]
- 对于带有package的java程序怎么编译?怎么运行?
采用之前的编译方式和运行不行了,类名不再是:HelloWorld了,类名是:com.zh0u.javase.import_test.HelloWorld
编译:javac -d . HelloWorld.java。-d 带包编译,.代表编译之后生成的东西放到当前目录下(点代表当前目录)。
运行:java com.zh0u.javase.import_test.HelloWorld
package com.zh0u.interface_test;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
6.2 import
- import什么时候使用?
在A类中使用B类,如果A类和B类在同一个包下,不需要import,否则就需要使用import。
- import的用法。
import语句只能出现在package语句之下,class声明之上。
import语句还可以使用*的方式导入类。
import com.zh0u.接口.*;
java.lang包下面的直接类不需要使用import导入,直接可以使用。如:String.java。
7、访问权限控制Java访问级别修饰符主要包括:private、protected 和 public ,可以限定其他类对该类、属性和方法的使用权限。
| 修饰符 | 类的内部 | 同一个包里 | 子类 | 任何地方 |
|---|---|---|---|---|
| private | Y | N | N | N |
| default | Y | Y | N | N |
| protected | Y | Y | Y | N |
| public | Y | Y | Y | Y |
注意以上对类和接口的修饰只有 public 和 default ,内部类除外。
范围从大到小排序:public > protected > default > private
package com.zh0u.访问控制权限;
public class User {
// 给一些属性
// 私有
private int id;
// 受保护
protected int age;
// 公开
public int weight;
// 默认
String name;
// 方法
public void m1(){}
private void m2(){}
void m3(){}
protected void m4(){}
// 静态方法也可以使用四种访问权限修饰符
}
// java: 此处不允许使用修饰符private
// java: 此处不允许使用修饰符protected
// default
class J{}



