目录
一、面向对象与面向过程
面向过程强调的是功能行为,而面向对象强调的是具备功能的对象。面向过程程序设计,强调把”事情“当作核心,就像我们在前往某个地方时,如何前往、路线计划是什么、到达目的地后做什么,分成步骤来完成我们这件事情,在编程中各个具体的步骤就是一个个的函数。而面向对象程序设计则强调把”对象“当作核心,像是无需多虑直接滴滴打车,只需要告诉司机你的目的地就可以了,把人、事物看作一个对象,每一个对象都有自己的属性与行为,建立多个对象来解决整一个的问题而非分步解决。相较于面向过程,在完成某件任务时,我们不再像是一个执行者,而更像是一个指挥者。 由于面向对象具有封装,继承和多态的特性,因此面向对象的程序设计具有易维护,易扩展,易复用的优点。
二、封装(Encapsulation)
1、权限修饰符:(常使用private、public)
private | 只能在当前类中访问 |
---|---|
default | 只能在当前包内访问 |
protected | 只能在当前包与其派生包内访问 |
public | 谁都能访问 |
下面一段代码作为protected权限修饰符的应用展示:
/**
* @author Tweek
*/
public class Father {
/**
父类中的方法
*/
protected void method(){
System.out.println("U know I'm ur Father!");
}
}
/**
不同包下的子类
*/
import a.Father
public class Son extends Father {
/**
不同包下的子类可以访问父类在protected修饰下的方法,并继承该方法。
用super来调用
*/
@Override
public void method() {
super.method();
}
}
/**
测试类与子类在一个包内,但与父类无关,不是父类的派生类
*/
public class Test {
public static void main(String[] args) {
Son son = new Son();
/**
此时Test类中创建一个同包下的类的对象,调用同包下类的方法method
来到Son类中发现method内容需要super来调用
此时通过Son与Father的继承关系,Son用super调用了不同包下的Father中用protected修饰的方法
若Son中无super调用
Son类作为Father类的派生类可调用不同包下Father中用protected修饰的方法,而Test却不可通过Son对象来调用Son中的method方法,因为此时Son类中的method方法相当于Father类中的method方法,故Test作为Father不同包下的无关类,无法调用method方法。
*/
son.method();
}
}
控制台输出:
U know I'm ur Father!
2、JAVA封装
JAVA的封装一般是通过private修饰符来声明属性和方法实现的。
下面展示一段代码(JAVABEAN)体现数据封装:
public class Student {
private int age; //private封装属性age
private String name; //private封装属性name
public Student() {
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() { //用于获取属性age
return age;
}
public void setAge(int age) { //用于设置属性age
this.age = age;
}
public String getName() { //用于获取属性name
return name;
}
public void setName(String name) { //用于设置属性name
this.name = name;
}
}
/**
测试类
*/
public class Test(){
public static void main(String[] args) {
Student stu = new Student(21,"Tweek"); //Student(age,name)
System.out.println(stu.getName() + " " + stu.getAge());
}
}
控制台输出:
21 Tweek
三、继承(Extends)
1、继承
(1)关于继承的描述
继承所关联的有两种类,父类与子类,在继承关系中,应用继承所创建的新类称为子类,被继承的类称为父类。子类通过extends关键字来进行继承这一行为,产生继承关系后,子类会继承父类的属性与行为,由此可以扩展新的能力。
(2)继承的优点
1.继承使得代码更加简洁
2.提高代码复用性与维护性
(3)继承的特点
JAVA只支持单继承、不支持多继承,但支持多层继承
2、继承中成员访问特点
(1)成员变量
1.this:调用当前类中的成员变量
2.super:调用当前类的父类中的成员变量
3.在方法内出现与当前类成员变量相同的局部变量,若调用变量且无修饰词修饰变量,根据优先原则,优先调用局部变量
下面是代码示例:
/**
* @author Tweek
*/
public class ExtendsTest1 {
int age = 30;
public static void main(String[] args) {
Son son = new Son();
son.method();
}
}
class Son extends ExtendsTest1{
int age =20;
public void method(){
int age =19;
System.out.println(age);
System.out.println(this.age);
System.out.println(super.age);
}
}
控制台输出:
19
20
30
(2)成员方法访问特点
若在子类与父类中出现了方法声明一模一样的方法,在创建子类对象并调用其方法时,方法调用优先调用子类中的方法,这一操作称为方法重写。
下面是代码示例:
/**
* @author Tweek
*/
public class ExtendsTest1 {
int age = 30;
public void show(){
System.out.println("I'm Father");
}
public static void main(String[] args) {
Son son = new Son();
son.show();
}
}
class Son extends ExtendsTest1{
@Override
public void show() {
System.out.println("I'm Son");
}
}
控制台输出:
I'm Son
3、重写与重载
(1)重写(Override)
在父类与子类中,出现了一模一样方法声明的方法(方法名,参数,返回值),此时在继承关系中,子类方法重写父类方法,调用子类方法为优先逻辑。
当子类需要父类的方法而父类的方法不适用在当前情景中,子类重写父类方法可以对父类方法进行修改或增强操作
注意:1.父类中private方法不能被重写
2.子类重写父类方法时,访问权限必须大于等于父类
(2)重载(Overload)
在同一个类中,方法名相同而参数不同(类型不同、个数不同、顺序不同),与返回值无关,则称方法重载
下面展示有关重载代码:
/**
* @author Tweek
*/
public class ExtendsTest1 {
int age = 30;
public void show(){
System.out.println("I'm Father");
}
public static void main(String[] args) {
Son son = new Son();
son.show();
}
}
class Son extends ExtendsTest1{
/*
方法名相同,参数不同,出现方法重载
*/
public void show(int num) {
System.out.println("I'm Son");
}
}
控制台输出:
I'm father
四、多态(Polymorphism)
1、多态的定义
同一种行为具有多个不同表现形式或形态的能力。通俗点来说,就好比两个人都会唱歌,但是一个人擅长民族歌曲,另一个人擅长流行歌曲,在校园歌手大赛上,两个都会唱歌的人,却选择了风格迥异的歌曲了进行演唱这一行为。
2、多态的前提
(1)前提
1.有继承或实现关系
2.有方法重写
3.有父类引用指向子类对象
(2)多态的形式
满足前提条件后,代码可以产生两种类型的多态:
1.对象多态:方法的形参定义为父类类型,这个方法可以接受到父类的任意子类对象。如从本小节代码示例中的部分截取。
Singer tweek = new Tweek();
Singer jim = new Jim();
2.行为多态:同一个方法,具有多种不同的表现形式,或形态的能力。
下面代码示例,能让我们更好地理解:
/**
* @author Tweek
*/
public abstract class Singer {
/**
* People who can sing
*/
public abstract void sing();
}
public class Tweek extends Singer{
/**
* The one who can sing The Pop Music
*/
@Override
public void sing() {
System.out.println("I'm Tweek and I'm good at the pop music!");
}
}
public class Jim extends Singer {
/**
* The one who can sing The Ethnic Music
*/
@Override
public void sing() {
System.out.println("I'm Jim and I'm good at the ethnic music!");
}
}
public class Test3 {
/**
测试类
*/
public static void main(String[] args) {
Singer tweek = new Tweek();
Singer jim = new Jim();
tweek.sing();
jim.sing();
}
}
控制台输出:
I'm Jim and I'm good at the ethnic music!
I'm Tweek and I'm good at the pop music!
3、多态的成员访问特点
(1)成员变量
编译阶段看父类,运行阶段也是看父类。即编译阶段在父类中寻找成员变量,运行阶段以父类的成员变量运行。
(2)成员方法
编译阶段看父类,运行阶段看子类。即编译阶段寻找父类中的方法,子类继承并重写了父类的方法,故运行阶段走子类的方法逻辑。
下面是代码示例:
/**
* @author Tweek
*/
public abstract class Singer {
/**
* People who can sing
*/
public abstract void sing(); //父类中的方法
int num =20; //父类中的成员变量
}
public class Tweek extends Singer{
/**
* The one who can sing The Pop Music
*/
@Override
public void sing() {
System.out.println("I'm Tweek and I'm good at the pop music!"); //子类继承并重写了父类的方法
}
int num =30; //子类中的成员变量
}
public class Test3 {
/**
* 测试类
*/
public static void main(String[] args) {
Singer tweek = new Tweek(); //对象多态
tweek.sing(); //行为多态
System.out.println("num: "+tweek.num);
}
}
控制台输出:
I'm Tweek and I'm good at the pop music!
num: 20
4、多态的好处与弊端
(1)多态的好处
提高了程序的扩展性。即对象多态、行为多态的支持,同一个方法不同的形态。
(2)多态的弊端
不能使用子类的特有成员变量、方法
解决方法:利用多态的向下转型,调用子类中特有的成员变量、方法
5、多态的转型
(1)向上转型(Upcasting)
多态的向上转型,即父类引用指向子类对象(从子类到父类)。子类重写父类中的方法,通过父类引用指向子类对象,调用子类中的重写父类的方法。
代码示例(父类Singer,子类Tweek):
Singer tweek = new Tweek();
(2)向下转型(Downcasting)
将父类引用所指向的对象,转交给子类类型,即父类到子类。当父类创建对象实现子类多态时,因无法调用子类的特有成员,故此时需向下转型将实现的子类多态转交给子类类型,从而实现调用。此种转型需要强转型。
代码示例:
Tweek t = (Tweek)tweek;
(3)类型转换错误异常(ClassCastException)
出现异常的原因:在引用类型的强转中,实际类型和目标类型不匹配。
解决方法:
添加判断:判断类型是否匹配,在if语句中用instanceof判断(判断左边引用,是否是右边的数据类型)。
instanceof是Java中的二元运算符,作用是测试它左边的对象是否是它右边的类的实例,返回 boolean数据类型。当左边的对象是右边的类或子类所创建的对象时,返回true,否则,返回false。
下面的代码展示了可能会出现错误的情况:
Singer tweek = new Tweek();
Singer jim = new Jim();
Tweek t = (Tweek)tweek;
Tweek j =(Tweek)jim;
/**
在运行过程中第四行代码报错并抛出异常java.lang.ClassCastException。
tweek与jim都是Singer创建的对象,虽然第三、四行代码几乎相同,都是把Singer强制转换为Tweek,第三行代码的意思是把擅长流行乐的歌手Tweek转换为Tweek本身,第四行代码的意思是把擅长民乐的歌手Jim转化为Tweek本身,但Tweek会的技能,Jim不一定会或是根本不会,故此处产生了实际类型与目标类型不匹配。
*/
下面的代码展示在具体场景中的instance应用:
/**
* @author Tweek
*/
public class Tweek extends Singer{
/**
* The one who can sing The Pop Music
*/
@Override
public void sing() {
System.out.println("I'm Tweek and I'm good at the pop music!");
}
/**
Tweek子类的特有方法hobby()
*/
public void hobby(){
System.out.println("I'm Tweek and I like playing basketball!");
}
}
public class Jim extends Singer {
/**
* The one who can sing The Ethnic Music
*/
@Override
public void sing() {
System.out.println("I'm Jim and I'm good at the ethnic music!");
}
}
public class Test3 {
/**
* 测试类
*/
public static void main(String[] args) {
Singer singer = null;
Scanner in = new Scanner(System.in);
System.out.println("1.The Pop music Singer Tweek");
System.out.println("1.The Ethnic music Singer Jim");
System.out.print("请选择你想要的歌手:");
int choice = in.nextInt();
/**
* 选择你想要的歌手
*/
switch (choice){
case 1:
singer = new Tweek();
break;
case 2:
singer = new Jim();
break;
default:
System.out.println("无此歌手!");
break;
}
System.out.println("歌手自我介绍:");
if(singer instanceof Tweek){
Tweek tweek = (Tweek)singer; //向下转型
tweek.hobby(); //调用子类特定的方法
}
singer.sing();
}
}
第一次控制台输出:
1.The Pop music Singer Tweek
1.The Ethnic music Singer Jim
请选择你想要的歌手:1
歌手自我介绍:
I'm Tweek and I like playing basketball!
I'm Tweek and I'm good at the pop music!
第二次控制台输出:
1.The Pop music Singer Tweek
1.The Ethnic music Singer Jim
请选择你想要的歌手:2
歌手自我介绍:
I'm Jim and I'm good at the ethnic music!