——面向对象编程的优点
-
提高代码复用性
-
程序的使用者无需关心具体实现细节
-
程序的代码和功能比较清晰,便于进行维护
-
改变了程序员的思考习惯,更加符合人的思维习惯
面向对象三大特征
——封装
从形式上看,封装是将数据和行为组合在一个包中,并且对对象的使用者隐藏了数据的实现方式,给予了对象“黑盒”的特性,提高了重用性和可靠性。
/*封装的好处 1.信息隐藏——例如,电视内有很多复杂零件,通过各种按钮将内部的复杂结构给隐藏了。 2.简化操作——只需通过调频和音量等少量按钮,就可以操纵电视。 ——程序的基本封装单元是类,通过类的封装,既可以将代码单元化,又达到信息隐藏的目的。*/
封装的等级——访问权限控制
访问控制符 | 本类 | 同包 | 子类 | 所有 |
---|---|---|---|---|
private | ✔ | |||
默认 | ✔ | ✔ | ||
protected | ✔ | ✔ | ✔ | |
public | ✔ | ✔ | ✔ | ✔ |
eg:
public class Father {
private String name;
private String sex;
private int age;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
——继承(extends)
可以通过扩展一个现有的类来建立新的类,扩展后的新类具有它所扩展的类的全部属性和方法,在新类中只需要提供仅适用于这个类的新的属性和方法就可以了。
目的:实现代码的复用性 表示事物之间的关系
( Java 只支持单继承和多层继承,不允许多重继承)
eg:
子类
public class Student extends People{
private String school;
private String major;
Student(){
}
Student(String name,int age,String sex,String school,String major){
super(name,age,sex);//继承父类属性
this.school = school;
this.major = major;
}
@Override
void showlnfo() {
super.showlnfo();//调用父类
System.out.println(this.getName()+"在"+this.getSchool()+"就读"+"专业为:"+this.getMajor());
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
}
父类
public class People {
private String name;
private int age;
private String sex;
People(){
}
People(String name,int age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
void showlnfo(){
System.out.println(this.getName()+"性别"+this.getSex()+"今年"+this.getAge()+"岁了");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
main
Father f = new Father();
f.setName("小头爸爸");
f.setSex("男");
f.setAge(22);
f.eat();
f.say();
f.run();
f.like();
Son s = new Son();
s.setName("大头儿子");
s.eat();
s.say();
s.run();
s.like();
——多态
多态意味着不同的形式,同一类的对象调用相同的方法可以表现出不同的行为。需要和封装和继承特性协同合作,不能单独看待。
(接口)(抽象类)
引发条件
——继承引发的多态
子类重写了父类的方法(继承+重写)
通过父类引用调用方法(向上转型)
——接口引发的多态
类实现接口的方法(重写)
通过接口类型的引用来调用方法(向上转型)
补充
//向上转型 父亲的引用指向子类的对象
People p = new Student();
//向下转型 父亲的引用的对象是指向子类对象
Student s = (Student)p;
抽象类
——使用abstract关键字修饰的类就是抽象类
特征
——抽象类和普通的类一样有构造方法,和重载构造方法,但是不能创建实例。
——抽象类用来被继承(抽象类的作用就是来规定子类的行为)。
——没有方法体的方法为抽象方法,使用abstract关键字修饰。
public abstract void calculate();
没有方法体,以分号结束
——有抽象方法的类必须声明为抽象类,抽象类不是必须含有抽象方法的。 抽象方法在子类中必须要重写
接口
——主要用来描述类具有什么功能,而并不给出每个功能的具体实现,等到由类来实现接口时再实现具体的功能。
interface Flyable{
void fly();
}
接口的特点
——接口中所有的方法都会默认添加public abstract
——接口中定义的所有变量都是默认添加了 public static final,都是常量
——接口可以多实现、同时接口可以多继承接口
接口中的新方法
——静态方法
interface Flyable {
static void fly() {
…
}
}
——默认方法
interface Flyable {
default void fly() {
System.out.println("i flying");
}
}
eg:
1、计划出行, 整个出行计划包含出行方式、目的地和吃饭形式;根据天气情况选择。 (出行计划接口定义,定义好三个方法,分别是出行方法、目的地方法、吃饭方法) 方案(具体方案的实现要符合接口定义的规范,各自具体实现) : 如果天气为大热天,则自驾出行、到公园郊游,烧烤; 如果下雨天,则大巴集体出行,到度假村游玩,自助餐; 如果阴天凉爽,则徒步出行,环公园绕-圈,面包和矿泉水。 根据不同的天气条件,可选择出不同的出行方案。
接口M1
public interface M1 {
void t(String r);
void m(String r);
void eat(String r);
}
子类(实现)Travel
public class Travel implements M1{
public void t(String r) {
switch(r) {
case "大热天":
System.out.println("自驾出行");
break;
case "下雨天":
System.out.println("大巴集体出行");
break;
case "阴天":
System.out.println("徒步出行");
break;
}
}
public void m(String r) {
switch(r) {
case "大热天":
System.out.println("公园郊游");
break;
case "下雨天":
System.out.println("度假村游玩");
break;
case "阴天":
System.out.println("公园绕一圈");
break;
}
}
public void eat(String r) {
switch(r) {
case "大热天":
System.out.println("烧烤");
break;
case "下雨天":
System.out.println("自助餐");
break;
case "阴天":
System.out.println("面包和矿泉水");
break;
}
}
}
Main
import java.util.*;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
System.out.println("当前天气为:(大热天,下雨天,阴天)");
String rs = sc.nextLine();
M1 m1 = new Travel();
m1.t(rs);
m1.m(rs);
m1.eat(rs);
sc.close();
}
}
接口&抽象类
抽象类 | 接口 |
---|---|
可以有抽象方法和非抽象方法 | 只能有抽象方法。从JDK 8 开始,也可以有默认和静态方法 |
用expends继承,不支持多重继承 | 用implements实现,支持多继承 |
变量和方法没有默认修饰符 | 变量默认为public static final的 方法默认为public abstract |
abstract关键字声明 | interface关键字声明 |
类与对象
——类是对对象的抽象,对象是类的实际体现
重载与重写的区别
重载与重写的区别 | |
---|---|
重载 | 1.重载是一个类中多态性的一种表现 2.重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序) 3.重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准 |
重写 | 1.发生在父类与子类之间,子类重写父类的方法且不能降低父类方法访问权限 2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同 3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private) 4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常 |
super&this
super&this区别 | |
---|---|
super | 父类对象的引用 访问父类的成员方法,属性,构造方法, 不能在静态方法中使用 |
this | 当前类对象的引用 访问当前类的成员方法,属性,构造方法, 不能在静态方法中使用 |
final关键字
——final关键字的作用
修饰类 : 表明该类是最终类,不能被继承
修饰变量(包括域和局部变量):表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)
修饰方法:表明该方法是最终方法,不能被重写
可以搭配static关键字一起使用,来定义类常量,例如Math中的PI
public static final double PI = 3.14159265358
补充:
1、final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。 2、final修饰的变量是有引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生改变的。
成员属性与局部变量
成员变量 | 局部变量 | |
---|---|---|
声明的位置 | 直接声明在类中 | 方法形参或内部类代码块内、构造器内 |
修饰符 | private、public、static、final 等 | 不能用权限修饰符修饰,可以使用final |
初始化值 | 有默认初始化值 | 没有默认初始化值,必须显式赋值 |
内部加载位置 | 堆空间或静态域内 | 栈空间 |
变量作用域
——在类中变量定义的位置不同,其作用范围也不同
-
方法中定义的变量称作局部变量,只在方法中有效
-
方法中定义的变量在方法执行完后销毁
-
方法中可以访问类中的变量(成员变量)
-
块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。
-
方法级和块级的变量必须被显示地初始化,否则不能访问
成员变量初始化
成员变量类型 | 初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0D |
char | '\u0000' 空字符 |
boolean | false |
引用类型 | null空引用 |
static 关键字应用
1、static用来修饰类的成员,被这个关键字修饰的成员都只和类加载有关;
——类的各个对象会共享同一个成员。
2、用static修饰的成员变量就是静态成员变量
1.类加载的时候就初始化;
2.被所有实例共享,内存中仅有一个值;
3.使用类名进行访问;
3、用static修饰的方法就是静态方法
1.静态方法在类加载后就可以使用;
2.静态方法使用类名进行访问;
3.静态方法不能访问外部非静态成员;
4.静态方法中不能使用this关键字;
4、用static修饰的代码块就是静态代码块
1.静态代码块在类加载后执行;
2.静态代码块和静态方法相同,不能使用外部非静态成员;
3.静态代码块执行和静态变量的初始化顺序由代码从上到下顺序决定
5、可以使用static 关键字进行静态导入
//例如在源文件开始部分添加下面代码:
import static java.lang.System.*;
/*那么就可以在类中使用System类中的所有静态方法和静态域了,而不需要加类名前缀,例如*/
out.println("Hello Java");
内部类——在类的内部定义的类
1)成员内部类
public class Outer {
private int number;
class Inner{
private int age;
public void innerTest() {
System.out.println("我是内部类!!");
}
}
}
——特点
a. 创建成员内部类的对象必须依赖于外部类对象 如:外部类对象.new 内部类()的形式
b. 成员内部类中不能有static成员
c. 访问外部类的属性和方法可以通过如:外部类.this.xxxx 的形式
d. 外部类不能直接访问内部类的成员,必须通过内部类的对象
2)静态内部类
public class Outer {
private int number;
public static class Inner {
private int age;
public void innerTest() {
System.out.println("我是静态内部类!!");
}
}
}
——特点
a. 创建静态内部类对象不依赖于外部类对象,new 外部类.内部类()
b. 可以有static成员
c. 外部类不能直接访问静态内部类的非静态成员,仍需通过内部类对象
d. 静态内部类中不能访问外部类的非静态成员
3)局部内部类
public class Outer {
public void test() {
class Inner2{
public void test1() {
System.out.println("我是方法中的内部类(局部内部类)");
}
}
//局部内部类的初始化
Inner2 in2 = new Inner2();
in2.test1();
}
}
——特点
a. 只能在代码块、方法体内和作用域中使用
b. 局部内部类访问作用域中的局部变量时该变量需要定义为常量或等效常量
c. 可以修饰为abstract
4)匿名内部类
public static void main(String[] args) {
//成员内部类的初始化
Outter out = new Outter();
Outter.Inner inner = out.new Inner();
//静态内部类初始化
Inner1 in = new Inner1();
out.test();
}
——特点
a. 必须继承一个类或者实现一个接口,如果是抽象类或者接口,要求匿名内部类必须实现所有抽象方法
b. 不能定义构造方法
c. 可以定义代码块,用于实例初始化,但是不能定义静态代码块
d. 是局部内部类,符合局部内部类的特点(不能定义为抽象)