类和类之间具有一定的结构关系。
类的关系主要有两种:
或关系
“或关系”也称为“is a”关系,是“一般~具体”的结构关系;
与关系
“与关系”也称为“has a”关系,是“整体~部分”的结构关系。
消息能够使对象之间进行通信
方法是类的行为实现,一个方法有方法名、参数以及方法体
唯一性
每个对象都是唯一的,自身具有唯一的标识,系统通过该标识可以找到相应的对象。
在对象的整个生命周期过程中,其标识都是不变的;
不同的对象其标识也是不同的。
分类性
分类性是指将具有一致属性和行为的对象抽象成类,只反映与应用有关的重要性质,而忽略其他一些无关内容。
任何类的划分都是主观的,但必须与具体的应用有关。
继承性
继承性是指子类自动继承父类的属性和方法,这是类之间的一种关系。在定义和实现一个子类的时候,可以在一个父类的基础之上加入若干新的内容即可,原来父类中所定义的内容将自动作为子类的内容。
多态性
多态性是指相同的操作、过程可作用于多种类型的对象上并获得不同的结果。
不同的对象,收到同一消息可以产生不同的结果,即具有不同的表现行为,这种现象称为多态性。
类是组成Java程序的基本要素
是一类对象的原型
它封装了一类对象的状态和方法
类的定义:
public class ClassName {
//成员变量
//成员方法
}
字段(field)是类的属性,使用变量来表示的。
方法(method)是类的功能和操作,是用函数来表示的
class Student {
String name;
int age;
void sayHello() {
System.out.println("Hello",+name);
}
}
类名 对象名 = new 类名()
对象名.字段;
对象名.方法();
public class Demo {
public static void main(String[] args) {
// 1. 导包。
// 2. 创建,格式:
// 类名称 对象名 = new 类名称();
// 3. 使用其中的成员变量,格式:
// 对象名.成员变量名
Studnt stu = new Student();
// 改变对象当中的成员变量数值内容
// 将右侧的字符串,赋值交给stu对象当中的name成员变量
stu.name = "***";
stu.age = 18;
System.out.println(stu.name);
System.out.println(stu.age);
// 4. 使用对象的成员方法,格式:
// 对象名.成员方法名()
stu.sayHello();
}
}
使用的好处:
成员变量的默认值
数据类型 | 默认值 | |
---|---|---|
基本类型 | 整数(byte,short,int,long) | 0 |
浮点数(float,double) | 0.0 | |
字符(char) | ‘\u0000’ | |
布尔(boolen) | false | |
应用类型 | 数组,类,接口 | null |
一个对象,调用一个方法内存图
通过上图,我们可以理解,在栈内存中运行的方法,遵循"先进后出,后进先出"的原则。变量p指向堆内存中 的空间,寻找方法信息,去执行该方法。
但是,这里依然有问题存在。创建多个对象时,如果每个对象内部都保存一份方法信息,这就非常浪费内存 了,因为所有对象的方法信息都是一样的。
两个对象,调用同一个方法
对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。这样哪怕是多个对象,方法信息 只保存一份,节约内存空间。
一个引用,作为参数传递到方法中内存图
引用类型作为参数,传递的是地址值。
public class Car {
String color;//成员变量
public void driver() {
int speed = 80;//局部变量
System.out.println("时速"+speed);
}
}
概述:面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。 封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的 方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
原则:将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。
private的含义
private的使用格式
private 数据类型 变量名;
使用private修饰成员变量
public class Student {
private String name;
private int age;
}
提供getxxx方法/setxxx方法,可以访问成员变量
public class Student {
private String name;
private int age;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
this代表所在类的当前对象的引用(地址值),即对象自己的引用。
记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
this.成员变量名
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
小贴士:无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法, 一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。
修饰符 构造方法名(参数列表){
// 方法体
}
public class Student {
private String name;
private int age;
// 无参数构造方法
public Student() {}
// 有参数构造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
}
注意事项
- 如果你不提供构造方法,系统会给出无参数构造方法。
- 如果你提供了构造方法,系统将不再提供无参数构造方法。
- 构造方法是可以重载的,既可以定义参数,也可以不定义参数。
public class ClassName{
//成员变量
//构造方法
//无参构造方法【必须】
//有参构造方法【建议】
//成员方法
//getXxx()
//setXxx()
}
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。其中,多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类。
继承描述的是事物之间的所属关系,这种关系是: is-a 的关系。
class 父类 {
...
}
class 子类 extends 父类 {
...
}
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下:
class Fu { // Fu中的成员变量。
int num = 5;
}
class Zi extends Fu {
// Zi中的成员变量
int num2 = 6;
// Zi中的成员方法
public void show() {
// 访问父类中的num,
System.out.println("Fu num="+num);
// 继承而来,所以直接访问。
// 访问子类中的num2
System.out.println("Zi num2="+num2);
}
}
class ExtendDemo02 {
public static void main(String[] args) {
// 创建子类对象
Zi z = new Zi();
// 调用子类中的show方法
z.show();
}
}
演示结果:
Fu num = 5
Zi num2 = 6
如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下:
class Fu {
// Fu中的成员变量。
int num = 5;
}
class Zi extends Fu {
// Zi中的成员变量
int num = 6;
public void show() {
// 访问父类中的num
System.out.println("Fu num=" + num);
// 访问子类中的num
System.out.println("Zi num=" + num);
}
}
class ExtendsDemo03 {
public static void main(String[] args) {
// 创建子类对象
Zi z = new Zi();
// 调用子类中的show方法
z.show();
}
}
演示结果:
Fu num = 6
Zi num = 6
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰 父类成员变量,类似于之前学过的 this 。
使用格式:
super.父类成员变量名
子类方法需要修改,代码如下:
class Zi extends Fu {
// Zi中的成员变量
int num = 6;
public void show() {
//访问父类中的num
System.out.println("Fu num=" + super.num);
//访问子类中的num
System.out.println("Zi num=" + this.num);
}
}
演示结果:
Fu num = 5
Zi num = 6
Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能 直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员 变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对 应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码如下:
class Fu{
public void show(){
System.out.println("Fu类中的show方法执行");
}
}
class Zi extends Fu{
public void show2(){
System.out.println("Zi类中的show2方法执行");
}
}
public class ExtendsDemo04{
public static void main(String[] args) {
Zi z = new Zi();
//子类中没有show方法,但是可以找到父类方法去执行
z.show();
z.show2();
}
}
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
代码如下:
class Fu {
public void show() {
System.out.println("Fu show");
}
}
class Zi extends Fu {
//子类重写了父类的show方法
public void show() {
System.out.println("Zi show");
}
}
public class ExtendsDemo05{
public static void main(String[] args) {
Zi z = new Zi();
// 子类中有show方法,只执行重写后的show方法
z.show(); // Zi show
}
}
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从 而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下:
class Phone {
public void sendMessage(){
System.out.println("发短信");
}
public void call(){
System.out.println("打电话");
}
public void showNum(){
System.out.println("来电显示号码");
}
}
//智能手机类
class NewPhone extends Phone {
//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
public void showNum(){
//调用父类已经存在的功能使用super
super.showNum();
//增加自己特有显示姓名和图片功能
System.out.println("显示来电姓名");
System.out.println("显示头像");
}
} public class ExtendsDemo06 {
public static void main(String[] args) {
// 创建子类对象
NewPhone np = new NewPhone();
// 调用父类继承而来的方法
np.call();
// 调用子类重写的方法
np.showNum();
}
}
这里重写时,用到super.父类成员方法,表示调用父类的成员方法。
方法可以带参数,通过参数可以给方法传递数据
带参数
public void setName(String name) {
this.name = name;
}
带多个参数
public int add(int a, int b) {
return a+b;
}
根据参数的使用场合,可以将参数分为:
形参: “声明方法”时给方法定义的形式上的参数,此时形参没有具体的数值,形参前必须有数据类型,格式为:
方法名(数据类型 形参)
实参:“调用方法”时程序给方法传递的实际数据,实参前面没有数据类型,格式为:
对象名.方法名(实参)
实参和形参之间传递数值的方式有两种:
值传递(call by value)
值传递时,实参和形参在内存中占不同的空间,当实参的值传递给形参后,两者之间将互不影响
引用传递(call by reference)
引用传递是将实参的“地址”传递给形参,被调方法通过传递的地址获取其指向的内存空间,从而在原来内存空间直接进行操作。
当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?
首先我们要回忆两个事情,构造方法的定义格式和作用。
class Fu {
private int n;
Fu(){
System.out.println("Fu()");
}
}
class Zi extends Fu {
Zi(){
// super(),调用父类构造方法
super();
System.out.println("Zi()");
}
}
public class ExtendsDemo07{
public static void main (String args[]){
Zi zi = new Zi();
}
}
输出结果:
Fu()
Zi()
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空 间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。理解图解如下:
访问成员
this.成员变量 ‐‐ 本类的
super.成员变量 ‐‐ 父类的
this.成员方法名() ‐‐ 本类的
super.成员方法名() ‐‐ 父类的
访问构造方法
this(...) ‐‐ 本类的构造方法
super(...) ‐‐ 父类的构造方法
子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。 super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。
Java只支持单继承,不支持多继承。
Java支持多层继承(继承体系)。
顶层父类是Object类。所有的类默认继承Object,作为父类。
子类和父类是一种相对的概念。
语法:
Person p = new Person();
1、package语句必须作为Java源文件的第一条非注释性语句;
2、一个Java源文件只能指定一个包,即只有一条package语句,不能有多条package语句;
3、定义包之后,Java源文件中可以定义多个类,这些类将全部位于该包下;
4、多个Java源文件可以定义相同的包。
在物理组织上,包的表现形式为目录,但并不等同于手工创建目录后将类拷贝过去就行,必须保证类中代码声明的包名与目录一致才行。为保证包名的规范性,建议以“公司域名反写.项目名.模块名”创建不同的子包,例如:com.qst.chapter03.comm包,“com.qst”是反写的公司域名,“chapter03”是项目名,“comm”是模块名。
Java中一个类可以访问其所在包中的其他所有的类,但是如果需要访问其他包中的类则可以使用import语句导入包。
语法
import 包名.*; //导入指定包中所有的类
import 包名.类名; //导入指定包中指定的类
导入包之后,可以在代码中直接访问包中的这些类。
指明导入当前包的所有类,但不能使用“java.”或“java..”这种语句来导入以java为前缀的所有包的所有类。一个Java源文件只能有一条package语句,但可以有多条import语句,且package语句在import语句之前。
4种访问控制级别:
访问控制表
访问控制 | private |
default |
protected |
public |
---|---|---|---|---|
同一类中成员 | + | + | + | + |
同一包(子类与无关类) | - | + | + | + |
不同包中子类 | - | - | + | + |
不同包中非子类 | - | - | - | + |
private、protected和public都是关键字,而friendly不是关键字,它只是一种缺省访问修饰符的称谓而已。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
private
,隐藏细节。public
,方便创建对象。public
,方便调用方法。不加权限修饰符,其访问能力与default修饰符相同
将字段用private
修饰,从而更好地将信息进行封装和隐藏
用setXXXX
和getXXXX
方法对类的属性进行存取,分别称为setter与getter。
这种方法有以下优点
private
更好地封装和隐藏,外部类不能随意存取和修改。getXXXX
方法,而不提供setXXXX
方法,可以保证属性是只读的class Person2 {
private int age;
public void setAge(int age) {
if(age > 0 && age < 200)
}
public int getAge() {
return age;
}
}
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
class 外部类 {
class 内部类 {
}
}
外部类.内部类 对象名 = new 外部类型().new 内部类型();
定义类:
public class Person {
private boolean live = true;
class Heart {
public void jump() {
// 直接访问外部类成员
if (live) {
System.out.println("心脏在跳动");
} else {
System.out.println("心脏不跳了");
}
}
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
定义测试类:
public class InnerDemo {
public static void main(String[] args) {
// 创建外部类对象
Person p = new Person();
// 创建内部类对象
Heart heart = p.new Heart();
// 调用内部类方法
heart.jump();
// 调用外部类方法
p.setLive(false);
// 调用内部类方法
heart.jump();
}
}
输出结果:
心脏在跳动
心脏不跳了
内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。
匿名内部类必须继承一个父类或者实现一个父接口。
new 父类名或者接口名() {
//方法重写
@Override
public void method() {
//执行语句
}
};
定义接口:
public abstract class FlyAble {
public abstract void fly();
}
创建匿名内部类,并调用:
public class InnerDemo {
public static void main(String[] args) {
/*
1.等号右边:是匿名内部类,定义并创建该接口的子类对象
2.等号左边:是多态赋值,接口类型引用指向子类对象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
};
//调用 fly方法,执行重写后的方法
f.fly();
}
}
当方法的形式参数是接口或者抽象类的时候,可以将匿名内部类作为参数传递:
public class InnerDemo2 {
public static void main(String[] args) {
/*
1.等号右边:定义并创建该接口的子类对象
2.等号左边:是多态,接口类型引用指向子类对象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
};
// 将f传递给showFly方法中
showFly(f);
}
public static void showFly(FlyAble f) {
f.fly();
}
}
以上两步,可以简化为一步:
public class InnerDemo03 {
public static void main(String[] args) {
/* 创建匿名内部类,直接传递给showFly(FlyAble f) */ showFly( new FlyAble(){
public void fly() { System.out.println("我飞了~~~"); }
});
}
public static void showFly(FlyAble f) {
f.fly();
}
}
基本含义 | 修饰类 | 修饰成员 | 修饰局部变量 | |
---|---|---|---|---|
static |
静态的、非实例的、类的 | 可以修饰内部类 | + | |
final |
最终的、不可改变的 | + | + | + |
abstract |
抽象的、不可实例化的 Yes | + | + |
关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属 于某个对象的。也就是说,既然属于类,就可以不靠创建对象来调用了。
当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改 该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。
定义格式:
static 数据类型 变量名
当 static 修饰成员方法时,该方法称为类方法 。静态方法在声明中有 static ,建议使用类名来调用,而不需要 创建类的对象。调用方式非常简单。
定义格式
修饰符 static 返回值类型 方法名 (参数列表){
// 执行语句
}
静态方法调用的注意事项:
- 静态方法可以直接访问类变量和静态方法。
- 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。
- 静态方法中,不能使用this关键字。
被static修饰的成员可以并且建议通过类名直接访问。虽然也可以通过对象名访问静态成员,原因即多个对象均属 于一个类,共享使用同一个静态成员,但是不建议,会出现警告信息。
// 访问类变量
类名.类变量名;
// 调用静态方法
类名.静态方法名(参数);
static 修饰的内容:
格式:
public class ClassName {
static {
//执行语句
}
}
作用:给类变量进行初始化赋值。
static 关键字,可以修饰变量、方法和代码块。在使用的过程中,其主要目的还是想在不创建对象的情况 下,去调用方法。下面将介绍两个工具类,来体现static 方法的便利。
final class 类名 {
}
修饰符 final 返回值类型 方法名(参数列表) {
//方法体
}
局部变量 --基本类型
public class FinalDemo1 {
public static void main(String[] args) {
// 声明变量,使用final修饰
final int a;
// 第一次赋值
a = 10;
// 第二次赋值
a = 20; // 报错,不可重新赋值
// 声明变量,直接赋值,使用final修饰
final int b = 10;
// 第二次赋值
b = 20; // 报错,不可重新赋值
}
}
局部变量 --引用类型
public class FinalDemo2 {
public static void main(String[] args) {
// 创建 User 对象
final User u = new User();
// 创建 另一个 User对象
u = new User(); // 报错,指向了新的对象,地址值改变。
// 调用setName方法
u.setName("张三"); // 可以修改
}
}
成员变量
显示初始化
public class User {
final String USERNAME = "zzz";
private int age;
}
构造方法初始化
public class User {
final String USERNAME ;
private int age;
public User(String username,int age) {
this.USERNAME = username;
this.age = age;
}
}
被final修饰的常量名称,一般都有书写规范,所有字母都大写。
父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有 意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法 的类就是抽象类
使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。
定义格式:
修饰符 abstract 返回值类型 方法名 (参数列表);
如果一个类包含抽象方法,那么该类必须是抽象类。
定义格式:
abstract class 类名字 {
}
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。
public class Cat extends Animal {
public void run (){
System.out.println("小猫在墙头走~~~");
}
}
public class CatTest {
public static void main(String[] args) {
// 创建子类对象
Cat c = new Cat();
// 调用run方法
c.run();
}
}
输出结果: 小猫在墙头走~~~
关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有 意义。
接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么 接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并 不是类,而是另外一种引用数据类型。
引用数据类型:数组,类,接口。
接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做 是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象 类。
public interface 接口名称 {
//抽象方法
//默认方法
//静态方法
//私有方法
}
抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。
public interface InterfaceName {
public abstract void method();
}
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
静态方法:使用 static 修饰,供接口直接调用。
public interface InterfaceName {
public default void method() {
//执行语句
}
public static void method2() {
//执行语句
}
}
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
public interface InterfaceName {
private void method() {
//执行语句
}
}
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类 似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。
非抽象子类实现接口:
class 类名 implements 接口名 {
//重写接口中的方法【必须】
//重写接口中默认方法【可选】
}
定义接口
public interface LiveAble {
//定义抽象方法
public abstract void eat();
public abstract void sleep();
}
定义实现类:
public class Animal implements LiveAble {
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void sleep() {
System.out.println("晚上睡");
}
}
定义测试类
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用实现后的方法
a.eat();
a.sleep();
}
}
输出结果:
吃东西
晚上睡
可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。
继承默认方法,代码如下:
定义接口:
public interface LiveAble {
public default void fly(){
System.out.println("天上飞");
}
}
定义实现类:
public class Animal implements LiveAble {
// 继承,什么都不用写,直接调用
}
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用默认方法
a.fly();
}
}
输出结果:
天上飞
重写默认方法,代码如下:
定义接口:
public interface LiveAble {
public default void fly(){
System.out.println("天上飞");
}
}
定义实现类:
public class Animal implements LiveAble {
@Override
public void fly() {
System.out.println("自由自在的飞");
}
}
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用重写方法
a.fly();
}
}
输出结果:
自由自在的飞
静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用,代码如下:
定义接口:
public interface LiveAble {
public static void run(){
System.out.println("跑起来~~~");
}
}
定义实现类:
public class Animal implements LiveAble {
// 无法重写静态方法
}
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// Animal.run(); // 【错误】无法继承方法,也无法调用
LiveAble.run(); //
}
}
输出结果:
跑起来~~~
如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。同学们在已学技术的基础上,可以自行测 试。
定义接口:
public interface LiveAble { default void func(){ func1(); func2(); } private void func1(){ System.out.println("跑起来~~~"); } private void func2(){ System.out.println("跑起来~~~"); } }
之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接 口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
实现格式
class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【不重名时可选】
}
[ ]: 表示可选操作。
接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。代码如 下:
定义多个接口:
interface A {
public abstract void showA();
public abstract void show();
}
interface B {
public abstract void showB();
public abstract void show();
}
定义实现类:
public class C implements A,B{
@Override
public void showA() {
System.out.println("showA");
}
@Override
public void showB() {
System.out.println("showB");
}
@Override
public void show() {
System.out.println("show");
}
}
接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。代码如下:
定义多个接口:
interface A {
public default void methodA(){
}
public default void method(){
}
}
interface B {
public default void methodB(){
}
public default void method(){
}
}
定义实现类:
public class C implements A,B{
@Override
public void method() {
System.out.println("method");
}
}
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执 行父类的成员方法。代码如下:
定义接口:
interface A {
public default void methodA(){
System.out.println("AAAAAAAAAAAA");
}
}
定义父类:
class D {
public void methodA(){
System.out.println("DDDDDDDDDDDD");
}
}
定义子类:
class C extends D implements A {
// 未重写methodA方法
}
定义测试类:
public class Test {
public static void main(String[] args) {
C c = new C();
c.methodA(); }
}
输出结果:
DDDDDDDDDDDD
一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用 extends 关键字,子接口继 承父接口的方法。如果父接口中的默认方法有重名的,那么子接口需要重写一次。代码如下:
定义父接口:
interface A {
public default void method(){
System.out.println("AAAAAAAAAAAAAAAAAAA");
}
}
interface B {
public default void method(){
System.out.println("BBBBBBBBBBBBBBBBBBB");
}
}
定义子接口:
interface D extends A,B{
@Override
public default void method() {
System.out.println("DDDDDDDDDDDDDD");
}
}
子接口重写默认方法时,default关键字可以保留。 子类重写默认方法时,default关键字不可以保留
对象数组就是一个数组中的所有元素都是对象,声明对象数组与普通基本数据类型的数组一样
语法:
类名[] 数组名 = new 类名[长度];
对象数组在内存中的存储
从JDK1.5起,可以使用枚举
enum Light{Red,Yellow,Green}
Light light = Light.Red;
switch(light){case Red;…;break;}
Java中的枚举是用class来实现的,可以复杂地使用
[public][abstract|final] class className [extends superclassName]
[implements InterfaceNameList] {//类声明
[public|protected|private] [static] [final] [transient] [volatile] type variableName;
//成员变量声明,可为多个
[public|protected|private] [static] [final|abstract] [native] [synchronized]
//方法定义及实现,可为多个
returnType methodName([paramList])
[throws exceptionList]{
statements
}
}
//接口声明
[public] interface InterfaceName [extends superInterface]{
//常量声明,可为多个
type constantName = Value;
//方法声明,可为多个
returnType metodName([paramList]);
}
构造方法
className([paramList]){
}
main()方法
public static void main(String[] args){
}
finalize()方法
protected void finalize() throws throwable {
}
package packageName; //指定文件中的类所在的包,0个或1个
import packageName.[className|*]; //指定引入的类,0个或多个
public classDefinition //属性为public的类定义,0个或1个
interfaceDefinition and classDefinition //接口或类定义,0个或多个。
编写一个小的程序,其中定义一些接口、类、抽象类,定义它们的成员(字段及方法), 要求使用setter/getter, static, final, abstract,@Override等语法要素,并写一个main函数来使用它们。这些类、接口可以是围绕以下选题之一
飞翔世界:来一次飞翔接力(即多个可飞翔的对象依次调用);
动物世界:来一次吃西瓜大赛;
图书馆:模拟一天的借阅过程;
学校:模拟选课过程;
等等
要求写个简要说明。
在本次练习中,我选择了飞翔世界作为练习。
定义接口Fly
public interface Fly {
void start();
void fly();
void stop();
}
定义抽象类AbstractFilter
abstract class AbstractFlier implements Fly {
@Override
public void start() {
System.out.println("START");
}
@Override
public void stop() {
System.out.println("END");
}
}
定义飞行员类:
class Flier extends AbstractFlier {
private String flier;
protected static final int DISTANCE = 1;
public void setName(String flier) {
this.flier = flier;
}
public void flying() {
System.out.println(this.flier + "\thas flown "+DISTANCE+"km");
}
@Override
public void start(){
System.out.println("========================");
System.out.println(this.flier+"\tstart flying");
}
@Override
public void fly() {
System.out.println(this.flier+"\tflying");
}
@Override
public void stop() {
System.out.println(this.flier+"\tstop flying");
}
}
主函数
public class FlyRelyDemo {
public static void main(String[] args) {
System.out.println("FlyRely START");
String flier1 = "pilot1";
String flier2 = "pilot2";
String flier3 = "pilot3";
Flier pilot1 = new Flier();
pilot1.setName(flier1);
pilot1.start();
pilot1.fly();
pilot1.flying();
pilot1.stop();
Flier pilot2 = new Flier();
pilot2.setName(flier2);
pilot2.start();
pilot2.fly();
pilot2.flying();
pilot2.stop();
Flier pilot3 = new Flier();
pilot3.setName(flier3);
pilot3.start();
pilot3.fly();
pilot3.flying();
pilot3.stop();
System.out.println("END");
}
}
效果:
FlyRely START
========================
pilot1 start flying
pilot1 flying
pilot1 has flown 1km
pilot1 stop flying
========================
pilot2 start flying
pilot2 flying
pilot2 has flown 1km
pilot2 stop flying
========================
pilot3 start flying
pilot3 flying
pilot3 has flown 1km
pilot3 stop flying
END
面向对象具有唯一性、分类性、继承性以及多态性四个特征
类是具有相同属性和方法的对象的抽象定义
对象是类的一个实例,拥有类定义的属性和方法
Java中通过关键字new创建一个类的实例对象
构造方法可用于在new对象时初始化对象属性
方法的参数传递有值传递和引用传递两种
类的方法和构造方法都可以重载定义
访问控制符用来限制类内部的信息(属性和方法)被访问的范围
Java中的访问修饰符有:public、protected、缺省、private
包可以使类的组织层次更鲜明
Java中使用package定义包,使用import导入包
静态成员从属于类,可直接通过类名调用
对象数组就是一个数组中的所有元素都是对象
对象数组中的每个元素都需要实例化