Java基础-面向对象
一、面向对象与面向过程
JAVA是一种纯面向对象程序设计(OOP)语言,程序中所有相关的程序运算或执行操作,都是利用由类产生的对象来控制
那什么是面向对象编程?和面向对象编程不同的,是面向过程编程。
①、什么是面向过程?
面向过程:
就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
举例:大象装进冰箱需要几步?
按照面向过程思想:
第一步:工作人员去打开冰箱门
第二步:把大象塞进冰箱
第三步:工作人员把冰箱门关上
诶,这里我们就看出来了,面向过程就是把一件事按步骤一步一步来实现
面向过程编程,是把模型分解成一步一步的过程。
②、什么是面向对象?
对象,就是对问题中的事物的抽象
面向对象:
就是把现实中的事物都抽象为“对象”。每个对象是唯一的,且都可以拥有它的属性与行为。我们就可以通过调用这些对象的方法、属性去解决问题。
冰箱作为一个对象;
大象作为一个对象。
冰箱有这些功能:开门、装物体、关门
面向对象的好处,就包括有很好的延展性,比如我给大象赋予了一个吃的功能,它通过调用就可以在冰箱里去吃东西。面向对象就是把现实问题抽象为对象,通过调用每个对象的属性或功能去解决问题。
二、面向对象
2.1. 什么是 Object(对象)
Object(对象)相当于中文语义“东西”。
Object 是指一个具体事物实例,比如飞机、狗、运气、哲学等看得见的,看不见得,有形的、无形的,具体的,抽象的都是对象,总之“一切皆 Object”。
2.2. 面向对象
面向对象(Object Oriented),是指面向客观事物之间的关系。人类日常的思维方式是面向对象的,自然界事物之间的关系是对象和对象之间的关系
面向对象的定义:
首先 根据客户需求抽象出业务对象;
然后 对需求进行合理分层,构建相对独立的业务模块;
之后 设计业务逻辑,利用多态、继承、封装、抽象的编程思想,实现业务需求;
最后 通过整合各模块,达到高内聚、低耦合的效果,从而满足客户要求。
2.3. 面向对象概念
- 类型(类):一个名词概念,如:客人、菜品、厨师
- 引用(变量):指引用具体概念实例的代词,如:某人、特价菜
- 对象(东西):指具体概念的个体实例,如:张三丰、一盘大盘鸡如上三者之间的关系可以体现为:“今天的特价菜是一盘大盘鸡,张三丰吃了”
- 行为:方法 eat() sleep()
- 多态:行为或引用,在具体情形下会发生变化的现象
比如:“一只动物”可以是“一匹马”、“一头驴”、“一只猴子”,多态的; “打”可以是“打酱油”、“打麻将”,“打人”,根据宾语发生变化多态的。 - 封装:任何对象实例都是尽可能封装, 减少暴露,它的实现细节对你是透明的(看不到)。
比如:只能看到汽车的壳子、轮胎等,看不到发动机。 - 继承:概念的继承关系。
2.4 面向对象的三大特征
封装可以隐藏实现细节,使得代码模块化;
继承可以**扩展已存在的代码模块(类);
它们的目的都是:代码重用。而多态则是为了实现另一个目的——接口重用!
多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
提高代码的复用性(OOP)
2.4.1 封装(encapsulation)/隐藏
一.四种访问控制级别
public:对外公开,访问级别最高
protected:只对同一个包中的类或者子类公开
默认:只对同一个包中的类公开
private:不对外公开,只能在对象内部访问,访问级别最低
二.封装的概念和原则:
概念:将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
原则:把所有的属性藏起来。
封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法(getter和setter方法)。
三.封装的好处:
使用封装有以下好处:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息,实现细节。
(说明:①面向对象的封装性本身并不是单单指private关键字;
②封装后的属性必须通过setter和getter进行访问。)
四.封装范式:
属性封装:private 属性类型 属性名称;
方法封装:private 方法返回值 方法名称(参数列表){}
封装类:
public class Student {
private String name;//属性封装
private int age;
public String getName() {//get方法获取
return name;
}
public void setName(String name) {//修改,添加判断条件
if(name.length()>0||name.length()<10){
this.name=name;
}else{
System.out.println("输入姓名格式有误!!!");
}
}
public void setAge(int age) {//修改,添加判断条件
if(age>=0&&age<=150){
this.age = age;
}else {
System.out.println("输入的年龄不符合规范!!");
}
}
public void StudentMessage(){//普通方法
System.out.println("学生姓名为:"+this.name+"学生年龄为:"+age);
}
}
测试类:
public class main {
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.StudentMessage();
}
}
五.get和set方法的使用:
①在创建对象过程中,我们常用private修饰,并且使用get与set方法对属性进行访问与修改。
②get/set+属性名(小驼峰命名法)。
③通过公共方法,简介操作类中的属性。
④扩展:被private修饰的属性,不能在外部访问与修改,这句话是错的,后期学习的反射可以。
⑤boolean类型的属性,用get与is方法。
public class Dog {
private String name;
private int age;
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;
}
}
采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
六.Java 包(package)
- 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。
包的作用:
1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
- Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口(Interface)、枚举(enumerations)和注释(annotation)等。
2.4.2 继承(extends)
- 子类继承父类(基类、超类)的属性和方法
- 构造器不能继承!
- 实例化子类,会递归分配所有父类的空间
- 子类构造器一定调用父类构造器
- 类一定有构造器(父类、子类)
继承:用来表达概念上具体化延续的具体概念。
继承:让某个类型的对象获得另一个类型的对象的属性和方法。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
- 1、子类拥有父类非private的属性和方法。
- 2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 3、子类可以用自己的方式实现父类的方法。
方法的重写(override)
- 在子类中可以根据需要对从基类中继承来的方法进行重写。
- 重写方法必须和被重写方法具有相同方法名称、参数列表和返回类型。
- 重写方法不能使用比被重写更严格的访问权限
重写与重载
重写(Override):子类中存在与父类的方法的方法名相同、参数相同、返回类型可以不同的方法。
- 父类与子类之间多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Override)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。
class A {
public void run(){
System.out.println("跑步");
}
}
class B extends A{
public void run(){
System.out.println("嘎嘎跑");
}
}
class mains{
public static void main(String[] args) {
B b = new B();
b.run();
}
}
重载(Overload):在一个类中定义多个方法名相同,而参数类型、数量或次序不同的方法。
- 一个类中多态性的一种表现。如果在一个类中定义了多个同名的方法,它们参数列表不同,则称为方法的重载(Overload)
public class Overload {
public Overload(){
System.out.println("请输入数字");
}
public Overload(int a,int b){
System.out.println(a+b);
}
public Overload(int a,int b,int c){
System.out.println(a+b+c);
}
public static void main(String[] args) {
new Overload();
new Overload(1,2);
new Overload(1,2,3);
}
}
区别: 重载实现于一个类中;
重写实现于子类中。
学习继承一定少不了这三个东西:构造器、protected关键字、向上转型
继承中的构造器
子类构造器一定调用父类构造器
- super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性
- 构造方法中:任何类的构造方法中,若是构造方法的第一行代码没有显示调用super(…),那么Java默认都会调用super()作为父类的初始化方法。所以super()写不写都无所谓
- 子类构造器一定调用父类构造器
public class ConstructorDemo {
public static void main(String[] args) {
Koo koo = new Koo(); // 调用子类对象
// 运行结果: FOO
}
}
class Foo{
public Foo(){
System.out.println("FOO");
}
}
class Koo extends Foo{// 继承Foo
public Koo(){
super(); // 调用父类无参构造器
//若是构造方法的第一行代码没有显示调用super(…)
// 那么Java默认都会调用super()作为父类的初始化方法。
}
}
注意:
如果父类没有无参数构造器,就必须在子类中明确指定调用父类的有参数构造器
public class ConstructorDemo {
public static void main(String[] args) {
Moo koo = new Moo(); // 调用子类对象
}
}
class Goo{
int a;
public Goo(int a){
this.a=a;
System.out.println(a);
}
}
class Moo extends Goo{// 继承Foo
public Moo(){
super(2); // 调用父类的有参数构造器
}
}
- 注:
子类构造器默认调用父类无参数构造器
super()表示调用父类构造器
使用 super()调用父类构造器,必须写在子类构造器第一行
this() 必须写在子类构造器第一行
有 super()就不能有 this(),两者互斥
protected关键字
java会继承父类中default权限以上的成员
private访问修饰符,对于封装而言,是最好的选择,但这个只是基于理想的世界,有时候我们需要这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到protected。
父类的private成员不会被子类继承,子类不能访问。
但是子类对象的确包含父类的私有成员。
2.4.3 多态(polymorphism)
多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
- 多态是同一个行为具有不同的表现形式或形态的能力
- 同一方法可以根据发送对象的不同而采用不同的行为方式
多态存在的三个必要条件
- 继承:在多态中必须存在有继承关系的子类和父类
- 重写:子类对父类中的某些方法进行重新定义
- 父类引用指向子类对象:Parent p = new Child();(向上转型)
多态的转型分为向上转型和向下转型两种:
向上转型:多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,
或者使用父类的功能就能完成相应的操作。
向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
示例:
public class Polymorphism {
public static void main(String[] args) {
// 父类类型 变量名=new 子类类型();
People p=new Student(); // 向上转型
p.eat(); // 调用方法
People t = new Teachers(); // 同上
t.eat();
// 使用子类特有功能时
// 子类类型 变量名=(子类类型) 父类类型的变量;
Student s = (Student)p;
s.study();
Teachers tea=(Teachers)t;
tea.teach();
}
}
class People{
public void eat(){
System.out.println("吃饭");
}
}
class Student extends People{
@Override
public void eat(){
System.out.println("吃冰糖葫芦");
}
public void study(){
System.out.println("好好学习");
}
}
class Teachers extends People{
@Override
public void eat(){
System.out.println("喝果茶");
}
public void teach(){
System.out.println("认真备课");
}
}
三、补充:抽象类与接口(Interface)
3.1 抽象类
3.1.1什么是抽象类
用abstract定义的类,具有抽象方法的类叫抽象类
3.1.2什么是抽象方法
只有方法的定义没有方法的实现
定义抽象方法的目的就是让,子类必须重写父类的抽象方法
3.2接口:
一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口:全部的方法都是抽象方法,全部的属性都是常量
- 接口是特殊的抽象类
- 接口用来表示纯抽象概念,没有任何具体的方法和属性
- 接口不能实例化,可以定义变量
Shape s = new Shape();
错 Shape s = new Circle(); 对 - 接口变量可以引用具体实现类的实例
- 接口只能被实现(继承),一个具体类实现接口,必须使用全部的抽象方法
- 接口之间可以继承(implements)
- 一个具体类可以实现多个接口,实现多继承现象 表示:一个概念即是 XXX 也是 XXX
- 接口中的属性,默认是常量 public static final
- 接口的方法一定是 public abstract 的(默认,可以不写)
- 实现一个接口,使用关键字 implements,实现实际上是一种继承关系 接口和实现类是父子类型的关系
抽象类与接口二者区别:
抽象类是对一种事物的抽象,即对类抽象
接口是对行为的抽象
示例:
一个接口就是描述一种能力,接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力。
声明格式:
[访问级别] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
public interface login {
// 接口只有方法的特征没有方法的实现
String username();// 声明变量
String password();// 声明变量
void success(); // 抽象方法
void failed(); // 抽象方法
}
实现类:
public class Logins implements login{
@Override
public String username() {
return "输入用户名";
}
@Override
public String password() {
return "输入密码";
}
@Override
public void success() {
System.out.println("登录成功");
}
@Override
public void failed() {
System.out.println("登陆失败");
}
}