首页 > 其他 > 详细

面向对象编程

时间:2020-07-13 15:38:04      阅读:43      评论:0      收藏:0      [点我收藏+]

面向对象编程

初识面向对象

面向过程思想:步骤清洗

面向对象思想:物以类聚,分类的思维模式 Objecy-Oriented Programming

以类的形式组织代码 以对象组织数据

抽象

先有对象 后有类

先有类 后有对象

方法回顾与加深

public class Demo01 {
    public static void main(String[] args) {
        
    }
    /*
    * 修饰符 返回值类型 方法名()
    * 方法体
    * 返回值
    * */
    public String sayHello(){
        return "Hello World!";
    }
    public void hello(){
        return;
    }
    public int max(int a,int b){
        return a>b?a:b;
    }
    public void readFile(String file) throws IOException{
    }
}

静态方法和非静态方法

public class Student {
    //静态方法
    public static void say(){
        System.out.println("我讲故事碍你哪疼了,跟个小棺材瓤子似的嗷嗷叫唤");
    }
    //非静态方法
    public void say2(){
        System.out.println("把嘴都给我关上");
    }
    public void say3(){
        System.out.println("妈妈号称活爷爷,讲出来的故事可好听了");
    }
}
public class Demo02 {
    public static void main(String[] args) {
        //静态方法
        Student.say();
        //非静态方法
        //实例化这个类
        //对象类型 对象名=对象值
        Student student = new Student();
        student.say2();
        new Student().say3();
    }
    //static是和类一起加载的,时间片很早
    public void a(){
        b();
    }
    //类实例化之后才存在
    public void b(){
    }
}

程序的运行效果
技术分享图片

技术分享图片

静态方法定义

public class Demo03 {
    public static void main(String[] args) {
        int add = Demo03.add(1,2);
        System.out.println(add);
    }
    public static int add(int a,int b){
        return a+b;
    }
}

方法定义的返回值如果是void的话,注意程序的运行结果

public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        String b = "Faye";
        change(a,b);
        System.out.println(a);
        System.out.println(b);
    }
    //返回值为空 输出结果为 1 Faye
    public static void change(int a,String b){
        a = 10;
        b = "Faye2";
    }
}

下面的案例中,方法修改了对象的属性,返回值为空表示这个对象本身不变,但是属性是可以改变的。

public class Demo05 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        Demo05.change(person);
        System.out.println(person.name);
    }
    public static void change(Person person){
        person.name = "Faye";
    }
}

//定义了一个Person类,有一个属性name
class Person{
    String name;
}

对象的创建分析

类和对象的关系

? 类是一种抽象的数据类型,不代表具体的事物

? 对象是抽象概念的具体实例

代码实例

创建了一个名为Student的类,类里面包含两部分内容,分别是属性和方法,在定义这个类的时候,会对属性自动默认初始化

public class Student {
    //属性:字段
    public String name;//null 加上public是因为后面的程序多起来之后好像不能在application中访问了,认定为访问不到
    public int age;//0
    //方法 this在代码中表示当前这个类
    public void study(){
        System.out.println(this.age+"岁的"+this.name+"神龙教主寿与天齐!");
    }
}
public class Application {
    public static void main(String[] args) {
        //类是抽象的,需要实例化
        //类实例化后会返回一个自己的对象,而且会默认初始化
        //s1对象就是Student类的一个具体实例
        Student s1 = new Student();
        s1.name = "Snow White";
        s1.age = 20;
        s1.study();
    }
}

运行效果:
技术分享图片

构造器

使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认初始化,并调用类中的构造器

构造器特点

类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的,并且构造器有以下两个特点

  1. 必须和类的名字相同
  2. 必须没有返回类型,也不能写void

创建一个最简单的类:

public class Ani { }

尽管这个类中什么都没有,其中也会存在一个构造方法,在它编译出来的class文件中可以观察到。

构造器作用

  1. 在使用new关键字的时候,必须要有构造器,因为其本质就是在调用构造器
  2. 构造器一般用来初始化值

构造器分类:

  1. 无参构造器:
  2. 有参构造器:如果只定义了有参构造器,那么在使用new关键字创建对象的时候就必须显示定义(换句话说就是new类后面括号里要符合有参构造器的结构)

视频课程演示代码如下:大致思想为建立一个Person类,然后建立了多个不同的构造器,在application中进行调用

//一个类即使什么都不写,也会存在一个方法
    //显式的定义构造器
public class Person {
    String name;
    int age;
    //实例化初始值
    //构造器的核心作用:1.使用new关键字必须要有构造器,其本质是在调用构造器 2.构造器一般用来初始化值
    public Person(){
        this.name = "Faye";
    }
    //有参构造:一旦定义了有参构造,无参构造就必须显示定义
    public Person(String name){
        this.name = name; //对象本身的name = 上面传下来的形参name
    }
    //alt+insert 构造器快捷键
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
/*
*     public static void main(String[] args) {
        //new 实例化对象
        Person person = new Person("Faye2");
        System.out.println(person.name);
    }
    * 构造器:
    * 1.和类名相同
    * 2.没有返回值
    * 作用:
    * 1.new本质是在调用构造器(构造方法)
    * 2.初始化对象值
    * 注意点:
    * 1.定义有参构造之后,如果想使用无参构造,显示的定义一个无参构造
    * Alt+insert
    * this.
* */

内存分析

这里介绍的是程序运行加载的顺序。

代码实例

首先建立两个类

public class Pet {
    public String name;
    public int age;
    public void shout(){
        System.out.println("bark");
    }
}
public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.name = "Kit";
        dog.age = 3;
        dog.shout();
        System.out.println(dog.name);
        System.out.println(dog.age);
        Pet cat = new Pet();
    }
}

技术分享图片

其运行顺序如下图所示:

  1. 首先在方法区加载类和静态方法区(也就是说静态方法最早加载),常量池中有一个“Kit”,同时还会将main方法压进栈中
  2. 在创建新对象的时候,先在堆里开辟空间,然后通过“引用变量名”指向这个开辟出的空间中的对象

技术分享图片

对象和类的总结

  1. 类与对象 类是一个抽象模板,对象是一个具体的实例

  2. 方法:定义调用

  3. 对象的引用:

    引用类型:对象是通过引用来操作的,栈——>堆(实际上指向的堆里面的地址)

    基本类型:大基本类型

  4. 属性:字段/Field/成员变量

    默认初始化

    ? 数字 0,0.0

    ? char:u0000

    ? boolean:false

    ? 引用:null

    属性的定义方式:修饰符 属性类型 属性名 = 属性值

    public int a = 10;
    
  5. 对象的创建和使用

    必须使用new关键字创造对象,也就是调用构造器来创建

    对象的属性

    对象的方法

    Person person = new Preson();
    person.name = "Faye";
    person.play() ;
    
  6. 静态的属性----->属性

    动态的行为----->方法

面向对象三大特征

封装

程序设计的追求是:高内聚(类的内部的数据操作细节自己完成,不允许外部干涉),低耦合(仅暴露少量的方法给外部使用)。

封装实际上是数据的隐藏,禁止直接访问一个对象中数据的实际表示,而通过接口来访问,称为信息隐藏。

关键词:属性私有,get用于访问/set用于设置

代码实例

public class Graduate {
    //利用private实现属性私有
    //name
    private String name;
    //ID number age
    private int id;
    private int age;
    //sex
    private char sex;
    //提供一个可以操作这个属性的方法
    //提供一些public的get、set方法
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }
    //alt+insert------>getter and setter
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    //可以对输入数据直接进行要求
    public void setAge(int age) {
        if (age>120||age<0){
            this.age = 3;
        }else{
            this.age = age;
        }
    }
}
public class Application {
    public static void main(String[] args) {
        Graduate g1 = new Graduate();
        g1.setName("Faye");
        System.out.println(g1.getName());
        g1.setId(11927050);
        System.out.println(g1.getId());
    }
}

封装的意义:

  1. 提高程序的安全性,保护数据
  2. 隐藏代码的实现细节
  3. 统一用户调用的接口,都是get/set
  4. 系统的可维护性增加了

继承

继承的本质是对某一批类的抽象

extands关键字,意思是扩展

JAVA中的类只有单继承,没有多继承(一个子类只能继承一个父类,但是一个父类可以有多个子类)

代码实例

编码思路:woman类和man类继承了friend类,并在application中进行调用

public class Friend{
    public int money = 10_000;
    public void say(){
        System.out.println("Nobody loves nobody.");
    }
    protected String name = "Faye";
    public void print(){
        System.out.println("王菲");
    }
    public Friend(){
        System.out.println("父类无参构造执行");
    }
}
public class Woman extends Friend{
    private String name = "Faye2";
    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
    public void print(){
        System.out.println("王菲2");
    }
    public void test1(){
        print();
        this.print();
        super.print();
    }
    public Woman(){
        super();//调用父类的构造器,必须要在子类构造器的第一行
        System.out.println("子类无参构造执行了");
    }
}
public class Man extends Friend { }

运行结果如下图所示:
技术分享图片

super注意点:

  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super必须只能出现在子类的方法或者构造方法中
  3. super和this不能同时调用构造方法!

this;

  1. 代表的对象不同 代表的是本身调用者 但是super代表父类对象的引用
  2. this没有继承也可以使用,super只能在继承条件下才能够使用
  3. 构造方法的区别:this()本类的构造,super()父类的构造

私有的内容不能被继承

多态

同一种方法可以根据发送对象的不同而采用多种不同的行为方式

一个对象实际的类型是确定的,但可以指向的对象的引用类型有很多

多态存在的条件

? 有继承关系

? 子类重写父类方法

? 父类引用指向子类对象

可实现动态编译

提高可扩展性

instanceof关键字

能否成功编译取决于前者的对象和后者的类之间是否存在父子/继承关系

? 以下面的代码举例:

? c1是city类对象,但是指向了hangzhou,那么它在object,city,hangzhou下都可成功编译,且都为true

? c2是hangzhou类对象,且指向了hangzhou,那么它在object,city,hangzhou下都可成功编译,且都为true;但是不能在beijing/string/其他不相关类型下编译

输出true/false取决于前者的对象和后者的类之间关系

代码实例

定义了city类和hangzhou类和beijing类

继承关系为:

Object>City(run)>Beijing(run eat)

Object>City(run)>Hangzhou(rain)

public class City {
    public void run(){
        System.out.println("run");
    }
}
public class Beijing extends City {
    @Override
    public void run() {
        System.out.println("run son");
    }
    public void eat(){
        System.out.println("eat son");
    }
}
public class Hangzhou extends City{
    public void rain(){
        System.out.println("rainy all day");
    }
}
public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        Beijing beijing = new Beijing();
        City city = new City();
        //可以指向的引用类型就不确定了:父类的引用指向子类
        //Beijing能调用的方法都是自己的方法或者继承父类的方法
        Beijing b1 = new Beijing();
        //City能指向子类,但是不能调用子类独有的方法
        City b2 = new Beijing();
        Object b3 = new Beijing();


        b2.run();//子类重写了父类的方法
        b1.run();

        //对象能执行哪些方法 主要看对象左边的类型,和右边的关系不大
        b1.eat();
        ((Beijing)b2).eat();//强制类型转换
        ((Beijing)b3).run();

        Object c1 = new Hangzhou();
        Hangzhou c2 = new Hangzhou();
        System.out.println(c1 instanceof Hangzhou);
        System.out.println(c1 instanceof City);
        System.out.println(c1 instanceof Object);
        System.out.println(c1 instanceof Beijing);
        System.out.println(c1 instanceof String);
        System.out.println(c2 instanceof Hangzhou);
        //System.out.println(c1 instanceof Hangzhou)能不能编译成功要看他们之间是否存在父子关系
        //然后看他们的关系确定输出
    }
}

小结

1.多态是方法的多态,属性没有多态

2.父类和子类要存在联系,否则会出现类型转换异常ClassCastException!

3.多态存在的条件:继承关系,方法重写,父类的引用指向子类对象! father f1 = new Son();

三种方法不能重写

? static方法属于类,不属于实例

? final属于常量

? private私有方法

方法重写

方法重写只和非静态方法有关

静态方法不能重写,其只和左边的类有关

代码实例

public class B {
    public void test(){
        System.out.println("B==>test");
    }
    public static void test1(){
        System.out.println("B=>test");
    }
}
public class A extends B {
    //重写 override
    @Override//注解
    public void test() {
        System.out.println("A==>test");
    }
    public static void test1(){
        System.out.println("A=>test");
    }
}
public class Application {
    public static void main(String[] args) {
        //静态方法:方法的调用只和左边的类型有关 即定义的数据类型有关
        //重写只和非静态方法有关,重写的只能是public
        A a = new A();
        a.test1();//A
        a.test();
        //父类的引用指向了子类
        B b = new A();//子类重写了父类的方法
        b.test1();//B
        b.test();
        //静态方法和非静态方法之间有区别
    }
}

运行结果如图所示:

技术分享图片

  • 重写需要有继承关系,子类重写父类的方法!属性不能重写
  • 1.方法名必须相同
  • 2.参数列表必须相同
  • 3.修饰符:重写的范围可以扩大 public protected default private
  • 4.抛出异常:范围可以被缩小,但不能扩大:ClassNotFoundException-->Exception(大)
  • 5.子类的方法和父类必须要一致,方法体不同
  • 为什么需要重写?
  • 1.子类不一定需要或不一定满足父类的功能
  • alt+insert override
  • 和重载区分开

抽象类

abstract修饰符可以用类修饰方法也可以用来修饰类,如果修饰方法,那么该方法就是抽象方法,如果修饰类,那么该类就是抽象类

抽象类中可以没有抽象方法,但是有抽象方法一定要在抽象类里(一定要声明为抽象类)

抽象类不能用new关键字来创建对象,它是让子类来继承的

抽象方法只有方法的声明,但是没有方法的事项,是用来让子类实现的

子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类

public abstract class Art {
    public abstract void createSomething();//只有方法名字 没有方法的实现
    public int test(int a,int b){
        return a+b;
    }
}
public class Painting extends Art{
    @Override
    public void createSomething() {

    }
}
public class Application {
    public static void main(String[] args) {
        Painting p1 = new Painting();
        int a = 1;
        int b = 2;
        int c = p1.test(a,b);//通过子类来调用
        System.out.println(c);
    }
}

思考题

抽象类中存在构造器吗?答案:依旧存在(看其编译的class文件)

抽象类存在意义是什么?答案:抽象出来公有属性,进行约束,和封装、继承、多态息息相关

举例说明:游戏中创建人物,最基础的人物的身高年龄等级职业等都有限制,但是玩家可以自行选择,并且可以自由命名捏脸等等,那么抽象类就可以定义为人物,其中提前private了有限制的属性,并通过(封装)get/set在相应的具体实现类中(继承)提供给玩家修改空间,在程序“设计人物”中,就可以调用这些已经存在了限制的用于具体实现的类(多态),最后成功建立了玩家需要的属性的人物角色。

接口

普通类:只有具体实现

抽象类:具体实现和规范都有

接口:只有规范!自己无法书写方法 存在的意义就是专业的约束 约束和实现过程分离开的重要标志:面向接口编程

规范:eg:“如果你是……,那么你必须……”=====>“如果你是三彬,那么你必须努力”/“如果你是大树,那么你必须是绿的”……

面向对象编程最重要的精髓就是对对象的抽象,最能体现这一点的就是接口;具有抽象能力的编程语言才有设计模式,才能合理地抽象

声明抽象的关键字是interface

代码实例

public interface UserService {
    //接口中的所有定义都是抽象的 public abstract
    //接口中定义的属性都是常量,但是很少在接口中定义常量
    int company = 99;
    public abstract void add(String name);//前面的关键字可以省略
    void delete(String name);
    void update(String name);
    void search(String name);
}
public interface TimeService {
    void timer();
}
public class UserServiceImpl implements UserService,TimeService{
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void search(String name) {

    }

    @Override
    public void timer() {

    }
}

小结

接口的作用:

1.约束

2.定义一些方法让不同的人实现
技术分享图片

方法都是public abstract,全是抽象方法,不能定义别的
技术分享图片

属性都是静态常量 public static final,不能定义别的,且没有默认初始化,必须手动初始化,否则会报错

接口不能被实例化 接口中没有构造方法

implements能够实现多个接口,实现了接口的类就要重写接口内的方法

内部类

内部类就是在一个类的内部再定义了一个类,比如A类中定义了一个B类,那么B类相对A类来说就称为内部类,而A类相对于B类来说就是外部类

代码实例

public class Outer {
    private int id1 = 11927050;
    private static int id2 = 11927050;
    public void out(){
        System.out.println("这是外部类方法");
    }
    
    public class Inner{
        public void in(){
            System.out.println("这是内部类方法");
        }
        public void getID1(){
            System.out.println(id1);
        }
    }
    
    //局部内部类
    public void method(){
        class Inner2{
            public void in(){}
        }
    }
    public static class InnerStatic{
        public void getID2(){
            System.out.println(id2);
        }
    }
    
    public static void main(String[] args) {
        //没有名字初始化类 不用将实例保存到变量中
        new O2().boring();
    }
}

//一个java文件中可以有多个class类,但只能有一个public class
class O2{
    public void boring(){
        System.out.println("boring");
    }
}
interface UserProblem{
    void hello();
}

成员内部类

静态内部类

局部内部类

匿名内部类

面向对象编程

原文:https://www.cnblogs.com/YabinWang/p/13292953.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!