【JavaSE学习专栏】第04篇 Java面向对象
文章目录
- 1 面向过程&面向对象
- 2 类和对象
- 2.1 对象的特征
- 2.2 java类及类的成员
- 2.3 类的语法格式
- 3 创建与初始化对象
- 3.1 类的成员之一:属性
- 3.2 类的成员之二:方法
- 3.3 类的成员之三:构造器(构造方法)
- 3.3.1 无参构造方法
- 3.3.2 有参构造方法
- 3.4 类的成员之四:初始化块
- 3.5 final关键字
- 4 四种访问权限修饰符
- 5 三大特性
- 5.1 封装
- 5.1.1 基本概念
- 5.1.2 封装的步骤
- 5.1.3 this关键字
- 5.1.4 方法的重载
- 5.2 继承
- 5.2.1 基本概念
- 5.2.2 案例
- 5.2.3 super关键字
- 5.2.4 方法重写
- 5.3 多态
- 5.3.1 基本概念
- 5.3.2 为什么使用多态
- 5.3.3 instanceof操作符
- 5.3.4 Object类
- 6 抽象类和抽象方法
- 6.1 基本概念
- 6.2 案例
- 7 接口
- 7.1 基本概念
- 7.2 接口的特点
1 面向过程&面向对象
-
面向过程思想
1.步骤清晰简单,第一步做什么,第二步做什么…2.面向过程适合处理一些较为简单的问题
-
面向对象思想
1.物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。2.面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
-
对于描述复杂的事务,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,任然需要面向过程的思路去处理。
2 类和对象
2.1 对象的特征
- 属性 :对象具有的各种特征,每个对象的每个属性都拥有特定值。例如:小张和小明的年龄、姓名不一样;
- 方法:对象执行的操作。
- 封装:对象同时具有属性和方法两项特性;对象的属性和方法通常被封装在一起,共同体现事物的特性, 二者相辅相承,不能分割。
2.2 java类及类的成员
- 属性:对应类中的成员变量
- 行为:对应类中的成员方法
2.3 类的语法格式
修饰符 class 类名{
属性声明;
方法声明;
}
说明:修饰符public:类可以被任意访问。类的正文要用{}括起来
package oop.Demo06;
public class Person {
//属性,成员变量,类的成员变量可以先声明,不用初始化,类的成员变量是有默认值
String name; //姓名,String的默认值是null
int age; //年龄,int的默认值是0
/**
* 打印姓名
*/
//行为,方法,也叫函数
public void showName(){ //方法的名称如果是多个单词,首个单词的首字母小写,其他单词首字母大写,这样就像严格驼峰一样,所以叫驼峰命名法。
System.out.println("名字:"+name);
}
/**
* 获取年龄
* @return
*/
public int getAge(){ //如果是一个有返回值的方法,那么方法的最后一行一定是返回相应的数据,使用关键字,返回的数据类型与方法定义的一致
return age;
}
}
- 类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物
1.动物、植物、手机、电脑…
2.Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为 - 对象是抽象概念的具体实列
1.张三就是人的应该具体实列,张三家里的旺财就是狗的一个拘役实列。
2.能够体现出特点,展现出功能的是具体的实列,而不是一个抽象的概念。
3 创建与初始化对象
- Java类的实例化,即创建类的对象
- 使用new关键字创建对象
- 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认初始化以及对类中构造器的调用。
- 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
1.必须和类的名字相同
2.必须没有返回类型,也不能写void - 构造器必须要掌握
3.1 类的成员之一:属性
- 语法格式:
修饰符 类型 属性名=初值;
说明:
修饰符private:该属性只能由该类的方法访问。
修饰符public:该属性可以被该类以外的方法访问。
类型:任何基本类型,如int、boolean或任何类。 - 举例
public class Person1 {
public String name="张三"; //public 公有的,这样的类变量可以在类的外部使用,也可以在本类的方法使用
private int age; //private私有的,不能在类的外部使用
}
3.2 类的成员之二:方法
- 语法格式
修饰符 返回值类型 方法名(参数列表){
方法体语句;
}
- 说明:
修饰符:public、private、protected等。
返回值类型:return语句传递返回值。没有返回值:void.
3.3 类的成员之三:构造器(构造方法)
-
构造器的特征
1.它具有与类相同的名称
2.它不声明返回值类型。(与声明void不同)
3.不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值。 -
构造器的作用:创建对象;给对象进行初始化
如:Order o = new Order();Person p=new Person(Peter,15);
package oop.Demo02;
public class Person {
//一个类既是什么都不写,它也会存在一个方法
//显示的定义构造器
String name;
int age;
//1.使用new关键字,必须要有构造器
//2.构造器用来初始化值
public Person(){
}
//有参构造:一旦定义了有参构造,无参就必须显示定义
public Person(String name){
this.name=name;
}
//alt+insert 快捷键
public Person(int age) {
this.age = age;
}
}
/*
//测试类
public class Application {
public static void main(String[] args) {
//new 实列化一个对象
Person person=new Person("小言");
System.out.println(person.name);
}
构造器:
1.和类名相同
2.没有返回值
作用:
1.new本质是在调用构造方法
2.初始化对象的值
注意点:
1.定义了有参构造之后,如果想使用无参构造,显示的定义一个无参构造
生成构造方法的快捷键:alt+insert
*/
3.3.1 无参构造方法
- 每一个类都有一个默认的无参构造方法;
- 无参构造方法的特点:
- 方法没有返回类型;
- 修饰符必须是public;
- 方法名必须与类名保持一致;
- 语法:public 类名(){}
- 构造方法什么时候执行:创建对象的时候就会执行一次构造方法!
- 自定义一个构造方法,可以覆盖它默认的无参构造!
3.3.2 有参构造方法
- 有参构造方法,在定义构造方法时可以给定参数
- 为了方便、在创建对象的时候就进行赋值,可以定义类的有参构造方法;
- 将传递过来参数值赋给成员变量,可以通过 this 关键字 区分:是成员变量还是局部变量;
- 语法:public 类名(参数类型 参数名…) { }
3.4 类的成员之四:初始化块
-
非静态代码块:没有static修饰的代码块
1.可以有输出语句。
2.可以对类的属性声明进行初始化操作。
3.可以调用静态和非静态的变量和方法。
4.若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
5.每次创建对象的时候,都会执行一次。且先于构造器执行。 -
静态代码块:用static修饰的代码块
1.可以有输出语句。
2.可以对类的属性声明进行初始化操作。
3.不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
4.若有多个静态代码块,那么按照从上到下的孙旭依次执行。
5.静态代码块的执行要先于非静态代码块。
6.静态代码块只执行一次。
Person类
package oop.Demo08;
public class Person {
String name;
static int age;
public Person(){
this.name="张三";
System.out.println("执行的是构造方法");
}
//非静态的代码块
{
System.out.println("执行的是非静态的代码块");
}
//静态代码块
static{
//这里只能使用静态修饰的属性和方法
age=18;
System.out.println("执行静态的代码块");
showAge();
}
public static void showAge(){
System.out.println(age);
}
}
/**
* 在程序的运行过程中,非静态代码块每次new对象都有重新执行
* 静态代码块只执行一次
*/
测试类
package oop.Demo08;
public class Test {
public static void main(String[] args) {
new Person();
new Person();
}
}
测试结果
3.5 final关键字
- 在Java中声明类、属性和方法时,可使用关键字final来修饰,表示“最终”。
- final标记的类不能被继承。提高安全性,提高程序的可读性。
- final标记的方法不能被子类重写。
- final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次。
- final标记的成员变量必须在声明的同时或在每个构造方法中或代码块中显示赋值,然后才能使用。(如:final double PI=3.14)
4 四种访问权限修饰符
Java权限修饰符public、protected、private置于类的成员定义前,用来限定对该类成员的访问权限。
修饰符 | 类内部 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
private | yes | |||
friendly | yes | yes | ||
protected | yes | yes | yes | |
public | yes | yes | yes | yes |
对于class的权限只可以用public和默认(friendly)。
public类可以在任何地方被访问
默认(friendly)类只能被同一个包内部的类访问。
5 三大特性
5.1 封装
5.1.1 基本概念
-
我们程序设计要追求”高内聚,低耦合“。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量方法给外部使用。
-
封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。 -
记住这句话就够了:属性私有,get/set
-
封装的意义:
1.提高程序的安全性,保护数据
2.隐藏代码的实现细节
3.同一接口
4.增加了系统的可维护性
5.1.2 封装的步骤
- 将变量设置为私有化;目的就是为了让其他类(外界的程序)不能直接访问。
/**
* 成员变量
* 封装第一步:将变量修饰为 private 私有的
*/
private String nikeName; //昵称
private String strain; //品种
private int health; //健康值
private int love; //亲密度
- 提供get/set方法;目的是为让其他类通过 get/set 进行访问和赋值。
/**
* 封装的第二步:
* 给私有变量提供 get/set方法
*/
//get 用来返回成员变量的值
public String getNikeName() {
return nikeName;
}
//set 用来接收变量的值
public void setNikeName(String nikeName) {
this.nikeName = nikeName;
}
//通过快捷键 alt + insert 生成 get/set方法
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
public int getHealth() {
return health;
}
/**
* 通过set 方法,可以让变量变得更安全,这里可以校验值的合法性
* @param health
*/
public void setHealth(int health) {
if(health < 1 || health > 100) {
System.err.println("健康值是1 ~ 100之间,请输入合法的健康值");
return;
}
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
5.1.3 this关键字
- this:代表当前类;
- this关键可以用来访问 变量、访问、构造方法;
- this关键字的用法:
- 调用属性
his.health = 100;
this.name = "小明";
- 调用方法
this.print();
- 调用构造方法
//调用当前类的无参构造
this();
//调用当前类的有参构造
this("小黑",10);
注:使用this关键字调用构造方法的话,必须在构造方法调用,必须在构造方法第一行调用!
5.1.4 方法的重载
- 重载就是在一个类中,有相同的函数名称,但形参不同的函数。
- 实现理论:
方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
- 方法的重载:同一个类里面,同名方法,参数不同(参数的个数,数据类型,顺序不同)
package method;
public class Demo01 {
//main方法
public static void main(String[] args) {
int sum= add(1,2);
System.out.println(sum);
int sum1=add(1,2,3);
System.out.println(sum1);
}
//加法
public static int add(int a,int b){
return a+b;
}
//方法的重载
public static int add(int num1,int num2,int num3){
return num1+num2+num3;
}
}
5.2 继承
- 语法
//1.编写父类
public class Pet {
共享的属性和方法
}
//2.编写子类,子类使用extens关键字继承父类
public class Dog extens Pet{
//子类继承了父类,就拥有父类的所有成员变量和方法
}
5.2.1 基本概念
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
- extends的意思是"扩展"。子类是父类的扩展。
- Java中类只有单继承,没有多继承!
- 继承是类和类之间的一种关系。除此之外,类和类之间还有以来、组合、聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用extends来表示。
- 子类和父类之间,从意义上讲应该具有"is a"的关系。
- 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
- 子类继承了父类,就继承了父类的方法和属性。
- 关于继承的规则:
子类不能直接访问父类中私有的(private)的成员变量和方法 - 作用
继承的出现提高了代码的复用性。
继承的出现让类与类之间产生了关系,提供了多态的前提。
不要仅为了获取其他类中某个功能而去继承。
5.2.2 案例
一个Person类
package oop.Demo06;
public class Person {
int age;
String name;
int sex;
public void showInfo(){
System.out.println(this.age);
System.out.println(this.name);
System.out.println(this.sex);
}
}
一个学生类,继承Person类
package oop.Demo06;
public class Student extends Person{
String school;
public void showInfo(){
System.out.println(this.age);
System.out.println(this.sex);
System.out.println(this.name);
System.out.println(this.school);
}
}
一个测试类
package oop.Demo06;
public class test {
public static void main(String[] args) {
Student stu1=new Student();
stu1.age=18;
stu1.name="小言";
stu1.sex="女";
System.out.println(stu1.name+"今年"+stu1.age+"岁了。");
}
}
测试结果
5.2.3 super关键字
- 在Java类中使用super来调用父类中指定操作:
- super可用于访问父类中定义的属性
super.nikeName
- super可用于调用父类中定义的成员方法
super.showInfo();
- super可用于在子类构造方法中调用父类的构造器
//访问父类无参构造方法
super();
//访问父类的有参构造方法
super(args..);
-
super注意点:
1.super调用父类的构造方法,必须在构造方法的第一个
2.super必须只能出现在子类的方法或者构造方法中!
3.super和this不能同时调用构造方法! -
super&this
1.代表的对象不同:
this:本身调用者的这个对象
super:代表父类对象的应用
2.前提
this:没有继承也可以使用
super:只能在继承条件小才可以使用
3.构造方法
this();本类的构造方法
super();父类的构造! -
子类可以调用由父类声明的构造方法。但是必须在子类的构造方法中使用super关键字来调用
5.2.4 方法重写
-
定义
在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。 -
要求
2.1 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型。
2.2 重写方法不能使用比被重写方法更严格的访问权限。
2.3 重写和被重写的方法必须同时为static的,或同时为非static的
2.4 子类方法抛出的异常不能大于父类被重写方法的异常 -
前提:需要有继承关系,子类重写父类的方法!
3.1 方法名必须相同
3.2 参数列表必须相同
3.3 修饰符:范围可以扩大但不能缩小:public>protected>default>private
3.4 抛出异常:范围,可以被缩小,但不能扩大 -
重写:子类的方法和父类必须一致:方法体不同!
5.3 多态
多态指的是:父类对象引用指向不同的子类。
5.3.1 基本概念
-
即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
-
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
-
多态存在的条件:
- 有继承关系
- 子类重写父类的方法
- 父类引用指向子类对象
-
注意:多态是方法的多态,属性没有多态性。
5.3.2 为什么使用多态
问题:如果再领养XXX宠物,并需要给XXX喂食,怎么办?
- 添加XXX类,继承Pet类,实现吃食方法;
- 修改Master类,添加给XXX喂食的方法。
注:从这个问题中可以看到,主人给宠物喂食,每次新加一个宠物,主人类都要新加一个喂食的方法。
这种情况会导致:需要频繁修改代码,代码可扩展性、可维护性差!
- 使用多态解决上述问题;
- 将主人喂食的方法,参数改成父类 Pet;通过多态的方式传递参数。
package com.oop.test3;
/**
* 主人类
* 多态:父类的对象引用指向不同的子类对象
*/
public class Master {
private String name; //主人名字
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 使用多态优化后的喂食方法
*/
public void feed(Pet pet) {
pet.eat();
}
}
- 测试
- 创建子类对象,调用 喂食方法,将子类作为参数传递过去,结果是可行的!
package com.oop.test3;
public class Test {
public static void main(String[] args) {
//1.创建一个狗狗对象
Dog dog = new Dog("小黑","拉不多", 50, 20);
//2.主人给狗狗小黑喂食
Master master = new Master();
master.setName("yoyo");
master.feed(dog);
//2.喂企鹅
Penguin p = new Penguin("QQ", Penguin.sex_FEMALE, 30, 10);
master.feed(p);
//3、喂鹦鹉
Yingwu yingwu = new Yingwu("咿呀");
master.feed(yingwu);
}
}
5.3.3 instanceof操作符
x instanceof A:检验x是否为类A的对象,返回值boolean型。
- 要求x所属的类与类A必须是子类和父类的关系,否则编译错误,
- 如果x属于类A的子类B,x instanceof A值也为true。
5.3.4 Object类
- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明父类,则默认父类为Object类。
6 抽象类和抽象方法
6.1 基本概念
- 用abstract关键字来修饰一个类时,这个类叫做抽象类;
- 用abstract来修饰一个方法时,该方法叫做抽象方法。
- 抽象方法:只有方法的声明,没有方法的实现。以分号结束:abstract int abstractMethod(int a)。
- 含抽象方法的类必须声明未抽象类。
- 抽象类不能被实例化。抽象类是用来作父类被继承的,抽象类的子类必须重写父类的方法,并提供方法体。若没有重写全部的抽象方法,任为抽象类。
- 不能用abstract修饰属性、私有方法、构造器、静态方法、final方法。
6.2 案例
一个抽象类
- 一般会将父类修饰为抽象类, 使用 abstract 修饰的类就是抽象类
package oop.Demo07;
//abstract 抽象类 本质是类 extends 单继承
//接口可以实现多继承
public abstract class Action {
//约束~有人帮我们实现~
//abstract,抽象方法,只有方法名字,没有方法的实现!
public abstract void doSomething();
//1.不能new这个抽象类,只能靠子类去实现它:约束!
//2.抽象类中可以写普通方法
//3.抽象方法必须在抽象类中
//抽象的抽象:约束
}
一个子类去继承此抽象类
package oop.Demo07;
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法
public abstract class A extends Action{
@Override
public void doSomething() {
}
}
7 接口
7.1 基本概念
-
有时必须从几个类中派生除一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
-
接口(interface)是抽象方法和常量值定义的集合。
-
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,从而没有变量和方法的实现。
-
实现接口类:
class SubClass implements interfaceA{} -
一个类可以实现多个接口,接口也可以继承其它接口。
7.2 接口的特点
- 用interface来定义。
- 接口中所有成员变量都默认是由public static final 修饰的。
- 接口中的所有方法都默认由public abstract修饰的。
- 接口没有构造器。
- 接口采用多层继承机制。
接口的定义举例:
package oop.Demo08;
//interface 定义的关键字 接口都需要实现类
public interface UserService {
//常量 public static final
int age=99;
//接口中的所有定义的方法其实都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
- 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,任为抽象类。
- 接口的主要用途就是被实现类实现(面向接口编程)
- 与继承关系类似,接口与实现类之间存在多态性。
- 如果实现接口的类中没有实现接口中的全部方法,必须将此类定义为抽象类