1. 面向对象
1.1. 类的定义
-
语法格式:
public class 类名称{ String name; //成员变量 public void eat(){ String first_name; //局部变量 }//成员方法 }
-
定义类: 就是定义类的成员,包括成员变量,成员方法
1. 对象的使用
-
创建对象:
类名 对象名 = new 类名();
-
使用对象访问勒种的成员:
对象名.成员变量; 对象名.成员方法;
2. 封装
1. 原则
- 讲成员变量进行隐藏,如果需要使用的时候,通过公共方法进行设置和获取
2. 步骤
- 使用
private
关键字来修饰成员变量。 - 对需要访问的成员变量,提供对应的一对
getXXX
方法、setXXX
方法
3. 封装的操作---private关键字
private的含义:
- private是一个权限修饰符,代表的是最小权限。
- 可以修饰成员变量和成员方法。
- 被private修饰后的成员变量和成员方法,只能在本类中进行使用
private的使用格式:
prviate 数据类型 变量名;
-
使用
private
修饰成员变量,代码public class Student{ private String name; private int age; }
-
提供
get
和set
方法,可以访问成员变量,代码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 num){ age = num; } public int getAge(){ return age; } }
4. 封装的关键字----this关键字
this的含义:
-
this代表坐在类的当前对象的(地址值), 即对象的自己的引用
| 记住: 方法被那个对象调用,那么this代表的是哪个对象
this的使用格式:
this.成员变量名;
使用this关键字修饰方法中的比那里,解决成员变量被隐藏的问题
public class Student{
private String name;
private int age;
public void setName(String n){
this.name = n;
}
public String getName(){
return name;
}
public void setAge(int num){
this.age = num;
}
public int getAge(){
return age;
}
}
小贴士:方法中只有一个变量名时,默认也是使用 this 修饰,可以省略不写。
5. 构造方法(类似于python中 new 方法)
- 当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
- 小贴士:无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。
构造方法的定义格式:
修饰符 类名称(参数列表){
// 方法体
}
public class Teach{
private String name;
private int age;
public Teach(){} // 无参构造 系统会默认赠送一个
public Teach(String name,int age){ // 带参数的构造
this.age = age;
this.name = name;
}
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;
}
}
构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。
注意事项:
- 如果你不提供构造方法,系统会给出无参数构造方法。
- 如果你提供了构造方法,系统将不再提供无参数构造方法。
- 构造方法是可以重载的,既可以定义参数,也可以不定义参数。
6. 标准化代码----JavaBean
JavaBean
是 Java语言编写类的一种标准规范。符合 JavaBean
的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的 set 和 get 方法
具体格式:
public class ClassName{
//成员变量
//构造方法
//无参构造方法【必须】
//有参构造方法【建议】
//成员方法
//getXxx()
//setXxx()
}
3. 继承
定义:继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
好处
- 提高代码的复用性。
- 类与类之间产生了关系,是多态的前提
1. 继承的格式
通过extends
关键字
public class 父类{
...
}
public class 子类 extends 父类{
...
}
-
案例:
public class Employee{ String name; //定义name属性 public void work(){ System.out.println("努力工作"); } } public class Teacher extends Employee{ // 定义打印name的方法 public void printName(){ System.out.println("name:"+name); } } public class testDemo{ public static void main(String[] args){ // 创建一个讲师的对象 Techer t = new Teacher(); // 进行name赋值 t.name = "孔老师"; t.printName(); t.work(); } }
2. 继承的特点---成员变量
成员变量不重名
-
如果子类和父类中出现不重名的成员变量,这是访问没有任何问题
public class Fu{ // Fu中的成员变量 int num = 5; }
public class Zi extents Fu{ // 子类的成员变量 int num2 = 10; public void show(){ // 访问父类的num System.out.println("Fu num:"+num); // 访问子类的num2 System.out.println("Zi num2:"+num2); } }
public class Demo{ public static void main(String[] args){ Zi z = new Zi(); z.show(); } } // 5 // 10
成员变量重名
-
使用格式
super.父类成员变量名
子类方法需要修改:
public class Zi extends Fu{ //子中的成员变量 int num = 10; public void show(){ System.out.println("Fu num:"+super.num); System.out.println("Zi num:"+this.num); } }
小贴士:
Fu
类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。
3. 继承后的特点---成员方法
成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代
-
代码:
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)
方法重写:
-
子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效 果,也称为重写或者复写。声明不变,重新实现。
public class Phone{ public void send(){ System.out.println("发短信"); } public void reverse(){ System.out.println("接电话"); } public void show(){ System.out.println("显示来电号码"); } }
public class NewPhone extends Phone{ public void show(){ super.show(); System.out.println("显示头衔"); System.out.println("显示姓名"); } }
public class testDemo{ public static void main(String[] args){ NewPhone nh = new NewPhone(); nh.show(); } }
小贴士:这里重写时,用到super.父类成员方法,表示调用父类的成员方法
注意事项
- 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
- 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
4. 继承后的特点--构造方法
1. 构造方法的定义格式和作用
-
构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
-
构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构 造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
代码:
public class Fu{ private int n; public Fu(){ System.out.println("我是父类的构造方法"); } }
public class Zi extends Fu{ public Zi(){ super(); //父类的构造方法 System.out.println("我是子类的构造方法"); } }
public class Demo{ public static void main(String[] args){ Zi z = new Zi(); } }
5. super和this
super和this的含义
- super :代表父类的存储空间标识(可以理解为父亲的引用)。
- this :代表当前对象的引用(谁调用就代表谁)。
super和this的用法
1. 访问成员
this.成员变量; ---本类的
super.成员变量; ---父类的
this.成员方法名(); ---本类的
super.成员方法名(); ---父类的
2. 访问构造
this(); -- 本类的构造方法
super(); -- 父类的构造方法
- 子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。
6. 继承的特点
java
只支持单继承,不支持多继承java
支持多层继承(继承体系)- 子类和父类是一种相对的概念
4. 抽象类
1. 什么是抽象类
1.定义
- 抽象方法: 没有方法体的方法
- 抽象类:包含抽象方法的类
2.使用格式
抽象方法
使用abstract
关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体
定义格式
修饰符 abstract 返回值类型 方法名(参数列表);
例子:
public abstract void run();
抽象类
如果一个类包含抽象方法那么这个类就是抽象类
定义格式
修饰符 abstract class 类名称{};
例子:
public abstract class Animal{
public abstract void run();
}
抽象的作用
继承抽象类的子类必须重写父类所有的抽象方法.否则,该子类也必须申明维持抽象类.最终,必须要有子类实现父类的抽象方法; 这种过程是: 实现方法
3. 注意事项
- 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
- 理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
- 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
- 理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
- 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象 类。
- 理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
5. 接口
1. 什么是接口
- 接口:一种引用数据类型,接口不可以创建对象,但是可以被实现
implements
。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法,否则就是一个抽象类
2.定义格式
public interface 接口名称{
// 抽象方法
// 默认方法
// 静态方法
//私有方法
}
含有抽象方法
抽象方法: 使用abstract
关键字进行修饰,可以省略,没有方法体,供子类进行实现使用
public interface 接口名字{
public abstract void 方法名称();
}
含有默认方法和静态方法
默认方法: 使用default
修饰,不可以省略,供子类调用或者子类重写。
静态方法:使用static
修饰,供接口直接调用。
public interface 接口名字{
public default void 方法名(){
// 执行语句
}
public static void 方法名(){
// 执行语句
}
}
含有私有方法和私有静态方法
私有方法:使用private
修饰,供接口中的默认方法或者静态方法调用
public interface 接口名称{
private void 方法名(){
// 执行语句
}
}
3.基本的实现
实现的概述
类与接口的关系为实现关系,即类实现接口,该类可以成为接口的实现类 使用implements
关键字
非抽象子类实现接口:
- 必须重写接口里面所有的抽象方法
- 继承接口的默认方法,可以直接调用,也可以重写
实现格式:
public class 类名 implements 接口名{
// 重写接口中的抽象方法
// 调用接口的默认方法或者重写
}
抽象方法的使用
必须全部实现
定义接口:
public interface 接口名{
// 定义抽象方法
public abstract void 抽象方法名1();
public abstract void 抽象方法名2();
}
定义实现类:
public class 类名 implements 接口名称{
@Override
public void 抽象方法名1(){
// 语句块
}
@Override
public void 抽象方法名2(){
// 语句块
}
}
定义使用类:(对象)
public class 类名称{
public static void main(String[] args){
// 创建子类对象
类名 类实例对象 = new 类名();
// 调用实现后的方法
类实例对象.抽象方法名1();
类实例对象.抽象方法名2();
}
}
默认方法的使用
可以重写,可以继承,只能通过实现类的对象来调用
1.继承默认方法
定义接口:
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();
}
}
2.重写默认方法
定义接口:
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){
LiveAble.run();
}
}
私有方法的使用
- 私有方法:只有默认方法可以调用
- 私有静态方法:默认方法和静态方法可以调用
定义接口:
public interface LiveAble{
default void func(){
func1();
func2();
}
private void func1(){
// 语句块
}
private void func2(){
// 语句块
}
}
4.接口的多实现
接口可以多实现
实现各式:
public class 类名 implements 接口1,接口2{
// 重写接口里面的抽象方法
// 重写接口中的默认方法(不重名可选)
}
抽象方法
如果抽象方法有重名,只需要写一次
定义多个接口:
public interface A{
public abstract void showA(){}
public abstract void show(){}
}
public interface B{
public abstract void show(){}
public abstract void showB(){}
}
定义实现类:
public class C implements A,B{
@Override
public void showA(){
// 语句块
}
@Override
public void showB(){
// 语句块
}
@Override
public void show(){
// 语句块
}
}
默认方法
如果默认方法有重名的,必须重写一次
定义多个接口:
public interface A{
public default void methodA();
public default void method();
}
public interface B{
public default void methodB();
public default void method();
}
定义实现类:
public class C implements A,B{
@Override
public void method(){
// 语句块
}
}
静态方法
接口中,存在同名的静态方法不会冲突。原因是通过接口名称访问静态方法
优先级问题
当一个类,既继承一个父类,又实现多个接口时,父类中的成员方法和接口中的默认方法重名时,子类选择父类的成员方法(就近原则)
接口的多继承
一个接口继承一个或者多个接口,接口继承使用extends
关键字
如果父类接口中有默认方法重名的,那么子类接口需要重写一次
- 子接口重写默认方法的时候,default关键字可以保留
- 子类重写默认方法时,default关键字不可以保留
5.其他成员特点
- 接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用
public static final
修饰 - 接口中,没有构造方法,不能创造对象
- 接口中,没有静态代码块
6. 多态
- 多态:指同一行为,具有多个不同表现形式
1.多态的体现
父类类型 变量名 = new 子类对象;
变量名.方法名();
父类类型:值子类对象继承的父类类型或者是实现父类接口类型
当时用多态方式调用方法时,首先先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是自而立重写后的方法
定义父类:
public abstract class Animal{
public abstract void eat();
}
定义子类:
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
}
定义测试类:
public class Test{
public static void main(String[] args){
//多态形式,创建对象
Animal a = new Cat();
a.eat(); // cat的eat
Animal b = new Dog();
b.eat(); // dog的eat
}
}
2.引用数据转换
1.向上转型
- 向上转型:多态本身就是子类向父类类型向上转换的过程,这个过程是默认的
当弗雷引用指向一个子类对象时,便是向上转型。
使用格式:
父类类型 变量名 = new 子类类型();
例子: Animal a = new Cat();
2.向下转型
- 向下转型:父类类型向子类类型向下转换的过程,这个过程就是强制的。
使用格式:
子类类型 变量名 = (子类类型) 父类变量名;
例子: Cat c = (Cat) a;
为什么要转型
当我们使用多肽调用方法的时候,首先是检查父类中是否有该方法,如果没有,则编译报错。也就是说,不能调用子类拥有,而弗雷没有的方法,编译出错。所以想要用子类特性的方法,必须向下转型。
定义类:
public abstract class Animal{
abstract void eat();
}
public class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
public void watchHouse(){
System.out.println("看家");
}
}
定义测试类:
public class Test{
public static void main(String[] args){
// 向上转型
Animal a = new Cat();
a.eat(); // cat的eat
// 向下转型
Cat c = (Cat) a;
c.catchMouse(); // cat的catchHouse
}
}
转型的异常
public class Test{
public static void main(String[] args){
// 向上转型
Animal a = new Cat();
a.eat(); // cat的eat
// 向下转型
Dog d = (Dog) a;
c.watchHouse(); // dog的watchHouse 运行报错
}
}
这段代码可以通过编译,但是会报错,报了classCatException
类型转换异常。因为我们创建的是一个Cat类型对象,运行的时候,不能转换为Dog对象,不符合转型的定义。为了避免这种情况,java提供了**instanceof
**关键字,对变量做类型的校验。
变量名 instanceof 数据类型
如果变量属于数据类型,返回true。
如果变量不属于数据类型,返回false。
所以,转换前进行判断
public class Test{
public static void main(String[] args){
// 向上转型
Animal a = new Cat();
a.eat(); // cat的eat
// 向下转型
if(a instanceof Cat){
Cat c = (Cat) a;
c.catchMouse(); // cat 的catchMouse
}else if(a instanceof Dog){
Dog d = (Dog) a;
d.watchHouse(); // dog的watchHouse
}
}
}
7.内部类
1.什么是内部类
将一个类A定义到另一个类B里面,里面的那个类A就是内部类,B就是外部类
成员内部类
- 成员内部类: 定义在类中方法外的类
定义格式:
public class 外部类{
public class 内部类{
}
}
代码举例:汽车和发动机
public class Car{ //外部类
public class Engine{
// 内部类
}
}
访问特点
-
内部类可以直接访问外部类的成员,包括私有成员
-
外部类访问内部类的成员,必须创建内部类的对象
-
创建格式:
外部类名.内部类名 对象名 = new 外部类型().new内部类型();
定义类:
public class Person{
private bpplean live = true;
public 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();
// 创建内部类对象
Person.Heart h = new Person().new Heart();
// 调用内部方法
h.jump();
// 调用外部类方法
p.setLive(false);
// 调用内部类方法
h.jump();
}
}
注意: 内部类是一个独立的类,在编译之后会在内部类会被编译成独立的.class
文件,但是前面必须是以外部类的类名和符号。 例如:
Person$Heart.class
2.匿名内部类
- 匿名内部类:是内部类的简化写法,本质是一个
带具体实现的父类或者是父接口的匿名的
子类对象。
使用接口的步骤:
- 定义子类
- 重写接口中的方法
- 创建子类对象
- 调用重写后的方法
前提
匿名内部类必须是一个继承一个父类或者实现一个父接口
格式
new 父类名或者接口名(){
//方法重写
@Override
public void method(){
// 执行语句
}
}
使用方式
接口为例子
定义接口:
public abstract class FlyAble{
public abstract void fly();
}
创建爱你匿名内部类并进行调用:
public class Demo{
public static void main(String[] args){
/*
1.等号左边:是多态赋值操作,接口类型引用子类对象
2.等号右边:是匿名内部类,定义并创建该接口的子类对象
*/
FlyAble f = new FlyAble(){
public void fly(){
System.out.println("我飞了");
}
};
f.fly();
}
}
通常在方法的形式参数是接口或者抽象类时,也可以将匿名对象作为参数
public class Demo2{
public static void main(String[] args){
/*
等号左边:是多态,接口类型引用指向子类对象
等号右边:定义并创建该接口的子类对象
*/
FlyAble f = new FlyAble(){
public void fly(){
System.out.println("我飞了");
}
};
// 将f传递给showFly方法中
showFly(f);
}
public static void showFly(FlyAble f){
f.fly();
}
}
简化:
public class Demo3{
public static void main(String[] args){
showFly(new FlyAble(){
public void fly(){
System.out.println("我飞了");
}
});
}
public static void showFly(FlyAble f){
f.fly();
}
}