面向对象编程_面向对象编程思想 - CSDN
精华内容
参与话题
  • 什么是面向对象程序设计

    万次阅读 2019-09-23 13:23:40
    1.面向对象和面向过程区别→2.什么是对象→3.什么是消息→4.什么是封装→5....面向过程程序设计:所谓的面向过程程序设计就是函数的定义和调用。简单地说,过程就是程序执行某项操作的一段代码,函...

    目录(可以点击相应标题快速定位)

    1.面向对象和面向过程区别 → 2.什么是对象 → 3.什么是消息 → 4.什么是封装→ 5.什么是多态 → 6.面向对象的优点:


    本文介绍 C++基础概念和知识。如果您想看其他语言(如 java)的语法,本文不涉及。

    1.面向对象和面向过程区别

    面向过程程序设计:所谓的面向过程程序设计就是函数的定义和调用。简单地说,过程就是程序执行某项操作的一段代码,函数是最常用的过程。

    面向对象程序设计:面向对象程序设计就是对象加消息。第一,程序一般由类的定义和使用两部分组成,而类的实例即对象;第二,程序中的一切操作都是通过对象发送消息来实现的,对象接收消息后,启动有关方法完成相应的操作。

    2.什么是对象

    对象可以理解为:用现实生活中来表述是属性+行为,用程序语言来表述是数据(变量)+操作(函数);

    对象需要有以下四点特征:

    ①每一个对象必须有一个名字以区别与其他对象(类的实例)。对于对象来说,每一个对象的数据成员都有其自己独立的存储空间,不同对象的数据成员占有不同的存储空间,而不同对象的成员函数是占有同一个函数代码段的。

    ②用属性来描述他的某些特征(数据赋值)。

    ③有一组操作,每个操作决定对象的一种行为(函数调用)。

    ④对象的操作可以分为两类:一类是自身所承受的操作,另一类是施加于其他对象的操作。

    3.什么是消息 

    一个对象与另一个对象之间的交互称之为消息。对象之间的联系只能通过消息传递来进行,且具有以下 3 个性质:

    ①同一个对象可以接收不同形式的多个消息,做出不同的相应。

    ②相同形式的消息可以传递给不同的对象,所做出的相应可以是不同的。

    ③对消息的相应并不是必须的,对象可以响应消息,也可以不响应。

    实现消息传递的方法:

    调用对象中的函数就是向该对象传送一个消息,要求该对象实现某一行为(功能、操作)。对象所能实现的行为(操作),在程序设计中成为方法,他们是通过调用相应的函数(C++中成为成员函数)来实现的。

    #include <iostream>
    
    class ABC
    {
    public:
        void init(int i, int j)  //对应  2.中的③
        { a = i; b = j; }
        void show()
        { std::cout << a << "  " << b << std::endl; }
    private:
        int a, b;          //对应 2.中的②
    };
    
    int main()
    {
        ABC o1, o2;         //类的两个实例即对象;  对应 2.中的①
        o1.init(12, 34);    //对象的消息传递;
        o2 = o1;            //对象之间的消息传递; 
        o1.show();          //同一对象接收多个消息;对应3.中的①
        o2.show();          //不同对象接收同一消息;对应3.中的②
        return 0;
    }
    
    //output:
    //12  34
    //12  34

    4.什么是封装

    封装就是把数据和实现操作的代码(函数)集中起来放在对象内部(类),并尽可能的屏蔽对象的内部细节,不能从外部直接访问或修改这些数据(如类中的 private 数据)及代码(如类中函数的代码在外部调用函数时是不可以修改的,是能使用其提供的功能)。使用一个对象的时候只需要知道它向外界提供的接口形式(函数名+参数)而无需知道他的数据结构细节和实现操作的算法。

    封装的含义:一是将有关的数据和操作代码封装在一个对象中,各个对象相互独自、互不干扰。而是将对象中的某些数据与操作代码对外隐藏,只留下少量接口,以便于外界联系,接收外界消息。

    5.什么是多态

    多态是指不同的对象收到相同的消息时产生多种不同的行为方式。C++支持两种多态性,即编译时的多态性(重载:函数/运算符重载)和运行时的多态性(虚函数)。

    关于虚函数的相关内容可以点击:https://blog.csdn.net/qq_41291253/article/details/100079861

    6.面向对象的优点:

    ①提高程序可重用性:通过继承

    ②改善程序可维护性:不改变接口而维护接口内部程序实现,不影响用户。

    ③跟好的支持大型程序设计:分模块设计,做自己的接口,然后整合到一个系统中去。

    展开全文
  • JAVA面向对象编程

    千次阅读 2018-10-08 11:07:13
    目录 1.构造方法: 2.this 3.继承 4.父类 5.重写 6.重载 7.访问修饰符 8.单例的实现 9.修饰符:static,final,abstract 10.interface 接口 11.开闭原则: 12.内部类 特征:封装,继承,多态... 1.... 2....

     

    目录

    1.构造方法:

    2.this

    3.继承

    4.父类

    5.重写

    6.重载

    7.访问修饰符

    8.单例的实现

    9.修饰符:static,final,abstract

    10.interface  接口

    11.开闭原则:

    12.内部类

    特征:封装,继承,多态(,抽象)

    1.构造方法:

    构造器:
      构造方法(构造函数)
      1.构造器名称和类名一致
      2.没有返回值类型(8种基本类型,String,引用类型,void)
      3.一个类中可以有多个构造器,多个构造器靠参数列表(个数,顺序,类型)来区分
      4.构造器的调用:当类被实例化时调用(new)--通过(名+参数列表)调用
      5.如果你不给这个类提供构造器,JVM会给该类提供一个默认的无参的构造器
        如果你给这个类提供构造器,JVM不会给该类提供一个默认的无参的构造器
      作用:
      为了初始化对象方便,更合理的初始化对

    2.this

    this:当前类对象
      1. this.       
        当前类的属性和当前类的方法
     2. this()
         当前的构造器,只能写在构造器的第一句

    3.继承

         1 .A is B(A是B)
         2.关系是相对的
         3.java中只支持单继承

    4.父类

    super:父类的对象
     1. super.
               能调用父类的属性和父类的方法
     2. super()
        调用父类的构造--通过参数列表
        只能写在构造器的第一句

    5.重写

    重写:
          1.存在继承关系的两个类中方法
          2.方法的名称一样,参数列表一样,返回类型也一样

    6.重载

           在同一个类中的多个方法,方法的名称相同,参数列表不相同,返回类型无所谓

    7.访问修饰符

    1)、public, private, protected,默认都可修饰成员变量,成员方法。

    2)、public,默认 可修饰顶层类。

    3)、局部变量不能用访问修饰符。

    4)成员变量或成员方法的访问控制:

    位置

    private

    默认

    protected

    public

    同一个类

    同一个包内的类

    不同包内的子类

    不同包并且不是子类

    8.单例的实现

    单例:实例化出来的对象是同一个对象

    方法:写一个私有的,静态的构造

    1、通过静态方法实现

    代码:

    Public class Run{
    
           private static Run r=null;
    
           public static Run gerRun(){
    
                    if(r==null){
    
                              r=new Run();
    
    }
    
    Return r;
    
    }
    
    }
    
    Public class Transfer{
    
           Public static void main(String[] args){
    
                    Run ru=Run.getRun();
    
                    Sysetem.out.printlin(ru);
    
                    Run ru1=Run.getRun();
    
                    Sysetem.out.printlin(ru1);
    
    
    
    }
    
    }

    运行结果:

    Run @4554617c

    Run @4554617c

    2、通过静态块实现

    public class demo02 {
    
        private static demo02 d=null;
    
        static {
    
            if(d==null){
    
                d=new demo02();
    
            }
    
        }
    
        public static demo02 getdemo02(){
    
            return d;
    
        }
    
     public class demo01 {
    
        public static void main(String[] args) {
    
            demo02 d1=demo02.getdemo02();
    
            System.out.println(d1);
    
            demo02 d2=demo02.getdemo02();
    
            System.out.println(d2);
    
    
    
        }
    
    }
    运行结果:

    Run @4554617c

    Run @4554617c

    9.修饰符:static,final,abstract

    (一)static-静态

    1.static能修饰属性,方法,静态块

    2.static修饰的属性:是多个对象共有的一块空间

    3.static修饰属性,方法--可以不通过实例化对象得到,可以通过类名直接调用

    4.静态方法和静态块中只允许使用静态属性

    5.静态块是在类被加载时调用

    (二)final:常量

     1.final能修饰变量,方法,类

    2.final修饰变量:不能被第二次赋值

    3.final修饰方法:不能被重写

    4.final修饰类:不能被继承

    (三)abstract :抽象类

    1.用abstract 修饰的类就是抽象类

    2.抽象类中可以有属性,方法,还可以有抽象方法

            抽象方法:

                   A.用abstract 修饰的方法就是抽象方法

                   B.抽象方法只有方法的声明,没有方法的实现(没有{})

    3.抽象类不能实例化(new)

    4.使用: 用一个类去继承抽象类,并把这个抽象类中的所有抽象方法都“重写“,否则该类还是为抽象类

    5.可以有构造方法,只是不能实例化

    代码示例:

    //通过父类声明,子类实例化来使用这个抽象类
    public class Test{
        public static void main(String[] args){
            Person p=new Person_C();
            p.say();
            System.out.println(p.i);
        }
    }
    
    //由于抽象类不能实例化,通过继承实现抽象类,将所有抽象方法重写
    public class Person_C extends Person{
        public  void say(){
            System.out.println("你好");
        }
    }
    

     

    //抽象类,可以有属性,方法,抽象方法
    public abstract class Person{
        public int i=1;
        public abstract void say();
    }

     

    10.interface  接口

    1.用interface修饰的东西就是接口

    2.接口中可以有属性

                接口中默认的属性类型为public  static  final类型(可省略)

    3.接口中只能有方法的声明(或者抽象方法),不能有方法的实现

    4.接口不能被实例化

    5.用一个类去“实现”一个接口,实现的关键字是implements

       实现接口时必须把所有的方法声明都实现,否则该类是一个抽象类

    6.一个类可以实现多个接口,A extends B implements C,D,E

    7.接口允许多继承

    代码示例:

    //用iterface修饰的就是接口
    public interface Tools1{
        float G=9.8f;
    //public static final float G=9.8;接口中的属性默认为public static final类型,可以省略
    //接口中可以有方法的声明(或者抽象方法),不能有方法的实现
        public void usb();
    //接口中不能有构造方法
    }
    public interface Tools2{
        float PI=3.141592653f;
        public void circle(int r);
    }

     实现方式一: 

    //用一个类去“实现”接口需要有implement关键字,接口可以多继承
    public class PC implement Tools1,Tools2{
        //要对接口中的所有方法实现重写,否则该类是一个抽象类
        @override
        public void usb(){
            System.out.println("PC's usb.")
        }
        @override
        public void circle(int a){
            System.out.println(2*a*PI);
        }
    }

     实现方式二:

    //一个类可以实现多个接口
    public class Test1 extends Demo implements Tools1,Tools2{
        public static void main(String[] args) {
            Test1 t=new Test1();
            t.circle(15);
            t.usb();
    
        }
        @Override
        public void usb() {
            System.out.println("usb()");
        }
    
        @Override
        public void circle(int r) {
            System.out.println(2*r*PI);
        }
    }

     

     

    补充:满足继承关系的时候使用抽象类,不满足抽象关系的时候使用接口,但是我们日常工作中都使用的是接口。

    11.开闭原则:

    对扩展(继承,接口)开发,对修改关闭

    12.内部类

    代码示例:

    public class A {
        int a=10;
    //    内部类的实例化:内部类不能直接被实例化,在外部类实例化一个内部类对象
        public B bbb=new B();
        public void say(){
            System.out.println("...A...say()...");
        }
        class B{
            int b=100;
            public void say(){
                System.out.println("...B...say()...");
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            A aaa=new A();
    //        内部类的调用
            aaa.bbb.say();
            System.out.println(aaa.bbb.b);
        }
    }

    父类声明,子类实例化的特点:

          对象是父类的对象,能调用父类的属性和方法,也能调用子类重写父类的方法

     

     

     

     

    展开全文
  • 面向对象编程思想

    千次阅读 2018-10-28 15:53:40
    Java面向对象编程思想Java对象什么是对象如何创建对象对象的生命周期继承什么是继承继承语法向上转型继承与初始化多态什么是多态产生正确的行为功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入...

    对象

    面向对象方式通过向程序员提供表示问题空间(问题存在的地方,如某个需求)中的元素的工具而更进一步。这种表示方式非常通用,使得程序员不会受限于任类型的问题。我们将问题空间中的元素及其在解空间(问题建模的地方,如计算机)表示称为“对象”。(你还需要一些无法类比为问题空间元素的对象。)这种思想的实质是:程序可以通过添加新类型的对象使自身适用于某个问题。

    什么是对象

    Alan Kay曾经总结了第一个成功的面向对象语言、同时也是Java所基于的语言之一 的Smalltalk的五个基本特性,这些特性表现了一种存粹的面向对象程序设计方式:

    1. 万物皆为对象:将对象视为奇特的变量,它可以存储数据,除此你还可以要求在自身上执行操作。理论上讲,你可求解任何概念化构件(狗、建筑物、服务等),将其表示为程序中的对象
    2. 程序是对象的集合,它们通过发送消息来告知彼此所要做的。要想请求一个对象,就必须对该对象发送一条消息。更具体地说,可以把消息想像为对某象的方法的调用请求。
    3. 每个对象都有自己的由其他对象所构成的存储。换句话说,可以通过创建包含现有对象的包的方式来创建新类型的对象。因此在程序中构建复杂的体系,同时将其复杂性隐在对象的简单性背后。
    4. 每个对象都拥有其类型。照通用的说法,“每个对象都是某个类(class)的一个实例(instance)”。每个类最重要的区别于其他类的特性就是“可以发送什么样的消息给它”。
    5. 某一特定类型的所有对象都可以接收同样的消息。这是一句意味深长的表述。如“圆形”类型的对象同时也是“几何形”类型的对象,所“圆形”对象必定能够接受发送给“几何形”对象的消息。这意味着可以编写与“几何形”交互并自动处理所有与几何形性质相关的事物的代码。这种可替代性是(Object Oriented Programming,OOP)OOP中最强有力的概念之一

    如何创建对象

    一般我们用new关键字创建一个对象,例如:

    String s = new String("asdf");
    

    这句话的意思大致为“给我一个新的【String】类型的对象,值为【asdf】”

    对象的生命周期

    1. 创建阶段(Created)
      1、首先创建对象会查找方法区是否加载了该类的.class文件,没有则java虚拟机加载该类的.class文件,并创建一个类型为Class的对象,这个时候类的所有静态初始化的动作都将执行。因此静态初始化只有在Class对象首次加载时进行一次。
      2、用new关键字创建对象时,java虚拟机将在堆内容上分配内存空间,内存空间会被清空
      4、初始化对象的所有基本类型数据,都设置成默认值而引用类型设置成null。
      一旦对象被创建,并有某个引用指向它,这个对象的状态就切换到了应用阶段

    2. 应用阶段(In Use)
      对象至少被一个强引用持有并且对象在作用域内

    3. 不可见阶段(Invisible)
      程序本身不再持有该对象的任何强引用,但是这些引用可能还存在着。简单说就是程序的执行已经超出了该对象的作用域了。

    4. 不可达阶段(Unreachable)
      该对象不再被任何强引用所持有。

    5. 收集阶段(Collected)
      当垃圾回收器发现该对象已经处于“不可达阶段”并且垃圾回收器已经对该对象的内存空间重新分配做好准备时,则对象进入了“收集阶段”。如果该对象已经重写了finalize()方法,则会去执行该方法。
      尽量不要重写finalize()方法,因为有可能影响JVM的对象分配与回收速度或者可能造成该对象的再次复活

    6. 终结阶段(Finalized)
      当对象执行完finalize()方法之后,仍然处于不可达状态时,则该对象进入终结阶段。在这个阶段,内存空间等待GC进行回收

    7. 对象空间重分配阶段(De-allocated)
      GC对该对象占有的内存空间进行回收或者再分配,该对象彻底消失

    继承

    什么是继承

    类型不仅仅只是描述了作用于一个对象集合上的约束条件,同时还有与其他类型之间的关系。两个类型可以有相同的特性和行为,但是其中一个类型可能比另一个含有更多的特性,并且可以处理更多的消息(或以不同的方式来处理消息)。继承使用基类型和导类型的概念表示了这种类的相似性。一个基类型包含其所有导出类型所共享的特性和行为。可以创建一个基类型来表示系统中某些对象的核心概念,从基类型中导出其他类型,来表示此核心可以被实现的各种不同方式。
    在这里插入图片描述
    这张UML图中的箭头从导出类(导出类、继承类、基类)指向基类(超类或父类),通常会存在一个以上的导出类

    继承语法

    使用extends实现类的继承,例如Chinese类继承了Person类:
    基类:

    public class Instrument {
    
    	public void play(Instrument p){
    		System.out.println("Instrument playing");
    	}
    }
    

    导出类:

    public class Wind extends Instrument{
    
    	@Override
    	public void play(Instrument  p) {
    		System.out.println("Wind Playing");
    	}
    	
    	public static void main(String[] args) {
    		Wind c = new Wind();
    		c.play(c);
    	}
    	
    }
    

    向上转型

    在上面例子中,play()方法可以接受Wind引用。鉴于java对类型的检查十分严格。接受某种类型的方法同样可以接受另外一种类型就会显得很奇怪,除非你认识到c对象同样也是一种Instrument对象,而且也不存在任play()方法是可以通过Instrument调用,同时又不存在Wind 之中,在play()中,程序代码可以对Wind 类和它所有的导出类起作用,这种将导出类引用转换为基类的引用的动作,我们称之为向上转型
    在这里插入图片描述
    由导出类转型成基类,在继承图上是向上移动因此一般称为向上转型。由于向上转型是从一个较专用类型向较通用类型转换,所以总是很安全的。也就是说,导出类是基类的一个超集。它可能比基类含有更多的方法但它必具备基类中所含有的方法。在向上转型的过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取它们。这就是为什么编译器在“未曾明确表示转型或“未曾指定殊标记”的情况下,任然运行向上转型的原因。

    继承与初始化

    在对上述例子进行加载的过程中。加载器开始启动并找出 Wind类的编译代码(在名为 Wind. class的文件之中)。在对它进行加载过程中,编译器注意到它有一个基类(这是由关键extends得知的)便会先加载基类,不管你是否打算产生基类的对象,这都要发生 。

    如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推。接下来根基类初始化(在此例中为 Instrument)即会被执行,然后是下一个导出类,以此类推。这种式很重要,因为导出类的static初始化可能会依赖于基类成员能否被正确初始化。

    至此为止,必要的类都已加载完毕,对象就可以被创建了。首先,对象中所有的基本类型都会被设为默认值,对象引用被设为null,这是通过将对象内存设为二进制零值而一举生成的。然后,基类的构造器会被调用。基类构造器和导出类的构造器一样,以相同的顺序来经历相同的过程。在基类完成之后,实例变量按其次序被初始化。最构造器的其余部分被执行。

    多态

    什么是多态

    多态是面向对象程序设计的最重要的妙诀:编译器不可能产生传统意义上的函数调用。一个非面向对象编程的编译器产生的函数调用会引起所谓的前期绑定,这么做意味着编译器将产生对一个具体函数名字的调用,而运行时将这个调用解析到将要被执行的代码的绝对地址。然而在OOP中,程序直到运行时才能够确定代码的地址。

    为了解决这个问题,面向对象程序设计语言使用了后期绑定(Java中除了static方法和final方法(private属于final方法)之外,其他所有的方法都是后期绑定)的概念。当对象发送消息时,被调用的代码直到运行时才能确定。编译器确保被调用方法的存在,并对调用参数和返回值执行类型检査(无法提供此类保证的语言被称为是弱类型的),但是并不知道将被执行的确切代码

    为了执行后期绑定,Java使用一小段特殊的代码来替代绝对地址调用。这段代码使用在对象中存储的信息来计算方法体的地址。这样,根据这一小段代码的内容,每一个对象都可以具有不同的行为表现。

    产生正确的行为

    向上转型可以像下面这么简单,我们继续使用上面的例子:

    Instrumentc i = new Wind();
    

    这里,创建了一个Wind对象,并把得到的引用立即赋值给i,这样做看似错误(将一种类型赋值给另一种类型);但实际上是没问题的,因为通过继承,Wind就是一种Instrument,因此编译器认可这条语也就不会产生错误信息。

    假设现在你调用一个基类方法(它已在导出类中被覆盖)

    i.play(i);
    

    你可能再次认为调用的是Instrument.play(),因为这毕竟是一个Instrument引用,那么编译器是怎样知做其他的事情呢?由于后期绑定(多态),还是正确调用Wind.play()方法。

    协变返回类型

    在Java SE5中添加了协变返回类型,它表示在导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型。如下例子

    class Grain{
    	public String toString(){
    		return "Grain";
    	}
    }
    
    class Wheat extends Grain{
    	public String toString(){
    		return "Wheat";
    	}	
    }
    
    class Mill{
    
    	public Wheat process(){return new Wheat();}
    	
    	public static void main(String[] args){
    		Grain g = new Grain();
    		Mill m = new Mill();
    		g = m.process();
    		System.out.println(g);
    	}
    }
    

    输出结果:

    Wheat
    

    向下转型与运行时类型识别

    通过向下转型—也就是在继承层次中向下移动—应该能够获取类型信息。然而,对于向下转型,例如,我们无法知道一个“几何形状”它确实就是一个“圆形”,它可以是一个三角形、正方形或其他类型。要解决这个问题,必须有某种方法来确保向下转型的正确性。使我们不致于贸然转型到错误类型,进而发出该对象无法接受的消息。这样做是极其不安全的。

    Java语言中,所有转型都会得到检査!所以即使我们只是进行一次普通的加括弧形式类型转换,在进入运行期时仍然会对其进行检査,以便保证它的确是我们希望的那种类型。如果不是,就会返ClassCastexception(类转型异常)。这种在运行期间对类型进行检查的行为称作“运行时类型识别(RTTI)”。

    final关键字

    根据上下文环境,Java的关键字final的含义存在着细微的区别,但通常它指的是“这是无法改变的”。不想做改变可能出于两种理由:设计或效率。由于这两个原因相差很远,所以关键字final有可能被误用 。以下谈论了可能使用到final的三种情况:数据、方法和类。

    1.final数据

    许多编程语言都有某种方法,来向编译器告知一块数据是恒定不变的。有时数据的恒定不变是很有用的,比如:

    1. 一个永不改变的始译时常量。
    2. 一个在运行时被初始化的值,而你不希望它被改变。

    对于编译期常量这种情况,编译器可以将该常量值代入任何可能用到它的计算式中,也就是说,可以在编译时执行计算式,这减轻了一些运行时的负担。在Java中,这类常量必须是基本数据类型,并且以关键字final表示。在对这个常量进行定义的时候,必须对其进行成赋值。

    一个既是static又是final的域只占据一段不能改变的存储空间。

    当对对象引用而不是基本类型运用final时,其含义会有一点令人迷感。对于基本类型,final使数值恒定不变,而用于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的,Java并未提供使任何对象恒定不变的途径(但可以自己编写类以取得使对象恒定不变的效果)。这一限制同样适用数组,它也是对象。

    public class Test {
    	
    	final static int I = 1;
    	final static double D = Math.random();
    		
    	public static void main(String[] args) {
    		System.out.print("i="+I+",d="+D);
    		I = 2;// Error :The final field cannot be assigned
    		final Test t = new Test();
    		t = new Test();//Error:cannot be assigned
    	}
    	//输出:i=1,d=0.6484902472577626
    }
    

    请注意,带有恒定初始值(即编译期常量)的final static基本类型全用大写字母命名,并且字与字之同用下划线隔开(这就像C常量一样,C常量是这一命名传统的发源地)。我们不能因为某数据是final的就认为在编译时可以知道它的值。示例部分在运行时使用随机生成的数值来初始化的D就说明了这一点。只有当数值在运行时内被初始化时才会显现,因为编译器对编译时数值,一视同仁(并且它们可能因优化而消失)。当运行程序时就会看到这个区别。

    空白final

    Java允许生成“空白final”,所调空白final是指被声明为final但又未给定初值的域。无论什么情况,编译器都确保空白final在使用前必须被初始化。但是,空白final在关键字final的使用上提供了更大的灵活性,为此,一个类中的final域就可以做到根据对象而有所不同,却又保持其恒定不变的特性。下面即为一例:

    class Poppet{
    	public final int I;
    	public Poppet(int i){
    		I = i;
    	}
    }
    
    public class Test{
    	public static void main(String[] args){
    		new Poppet(1);
    		new Poppet(2);
    	}
    }
    

    必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在。

    final参数

    Java允许在参数列表中以声明的方式将参数指明为final。这意味着你无法在方法中更改参数引用所指向的对象

    class Test{
    	public void f1(final Object o){
    		o =  new Object();//Error:variable o cannot be assigned.
    	}
    
    	public void f2(final int i){
    		i++;//variable i cannot be assigned.
    	}
    }
    

    2.final方法

    使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义。这是出于设计的考虑:想要确保在继承中使方法行为保持不变,并且不会被覆盖。

    过去建议使用final方法的第二个原因是效率。在Java的早期实现中,如果将一个方法指明为final,就是同意编译器将针对该方法的所有调用都转为内嵌调用。当编译器发现一个final方法调用命令时,它会根据自己的谨慎判断,跳过插入程序代码这种正常方式而执行方法调用机制(将参数压入栈,跳至方法代码处并执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来替代方法调用。这将消除方法调用的开销。当然,如果一个方法很大,你的程序代码就会膨胀,因而可能看不到内嵌带来的任何性能提高,因为,所带来的性能提高会因为花费于方法内的时间量而被缩减。

    在最近的Java版本中,虚拟机(特別是hotspot技术)可以探测到这些情况,并优化去掉这些效率反而降低的额外的内嵌调用,因此不再需要使用final方法来进行优化了。事实上,这种做法正在逐渐地受到劝阻。在使用JavaSE5/6时,应该让编译器和JVM去处理效率问题,只有在想
    要明确禁止覆盖时,才将方法设置为final的 。

    final和private关键字

    类中所有的private方法都隐式地指定为是final的。由于无法取用private方法,所以也就无法覆盖它。可以对private方法添加final修饰词,但这并不能给该方法增加任何额外的意义。

    这一问题会造成混淆。因为,如果你试图覆盖一个private方法(隐含是final的),似乎是奏效的,而且编译器也不会给出错误信息:

    class WithFinals{
    	private final void f(){
    		System.out.print("WithFinals.f()");
    	}
    }
    
    public class OverridingPrivate extends WithFinals{
    	private final void f(){
    		System.out.print("OverridingPrivate.f()");
    	}
    	
    	public void g(){
    		f();
    	}
    	public static void main(String[] args){
    		OverridingPrivate o = new OverridingPrivate();
    		o.g();
    	}
    	//输出:OverridingPrivate.f()
    }
    

    “覆盖”只有在某方法是基类的接口的一部分时才会出现。即必须能将一个对象向上转型为它的基本类型并调用相同的方法。如果某方法为private,它就不是基类的接口的一部分。它仅是一些隐藏于类中的程序代码,只不过是具有相同的名称而已。但如果在导出类中以相同的名称生成一个public、protected或包访问权限方法的话,该方法就不会产生在基类中出现的“仅具有相同名称”的情况。此时你并没有覆盖该方法,仅是生成了一个新的方法。由于private方法无法触及而且能有效隐藏,所以除了把它看成是因为它所归属的类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。

    3.final类

    当将某个类的整体定文为final时(通过将关键字final置于它的定文之前),就表明了你不打算继承该类,而且也不允许别人这样做。换句话说,出于某种考虑,你对该类的设计永不需要做任何变动,或者出于安全的考虑,你不希望它有子类。例:

    final class Diosaur{}
    
    class Further extends Diosaur{} //Error:Cannot extend final class 'Diosaur'
    

    请注意,final类的域可以根据个人的意愿选择为是或不是final。不论类是否被定义为final,相同的规则都适用于定文为final的域。然而,由于final类禁止继承,所以final类中所有的方法都隐式指定为是final的,因为无法覆盖它们。在final类中可以给方法添加final修饰词,但这不会增添任何意义 。

    有关final的忠告

    在设计类时,将方法指明是final的,应该说是明智的。你可能会觉得,没人会想要覆差你的方法。有时这是对的。但请留意你所作的假设。要预见类是如何被复用的一般是很困难的,特别是对于一个通用类而言更是如此。如果将一个方法指定为final,可能会妨碍其他程序员在项目中通过继承来复用你的类,而这只是因为你没有想到它会以那种方式被运用 。


    1. 本文来源《Java编程思想(第四版)》
    2. 对象生命周期原文:https://blog.csdn.net/sodino/article/details/38387049
    展开全文
  • 面向对象编程及其三大特性

    千次阅读 2019-06-11 11:39:23
    编程语言分为面向过程编程、函数式编程和面向对象编程。其实python就是一种面向对象编程,那么我们先了解一下它们的特点和优缺点以及它们的区别是什么。 面向过程编程:“面向过程”(Procedure Oriented)是一种以...

    编程语言分为面向过程编程、函数式编程和面向对象编程。其实python就是一种面向对象编程,那么我们先了解一下它们的特点和优缺点以及它们的区别是什么。

    面向过程编程:“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为 目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。

    面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程的思路是将数据与函数按照执行的逻辑顺序组织在一起,数据与函数分开考虑。

    • 特性:模块化   流程化
    • 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
    • 缺点:没有面向对象易维护、易复用、易扩展

    函数式编程: 函数式编程也是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。

    它的主要思想是把运算过程尽量写成一系列嵌套的函数调用。

    Python 不是也不大可能会成为一种函数式编程语言,但是它支持许多有价值的函数式编程语言构建。也有些表现得像函数式编程机制但是从传统上也不能被认为是函数式编程语言的构建。

    Python内建函数 : filter()、map()、reduce()、max()、min()

    面向对象编程:面向对象是按人们认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世界分析、设计、实现软件的办法。通过面向对象的理念使计算机软件系统能与现实世界中的系统一一对应。

    面向对象编程可以将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程。

    • 特性:抽象 封装 继承 多态
    • 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合  的系统,使系统更加灵活、更加易于维护
    • 缺点:性能比面向过程低

    可以拿生活中的实例来理解面向过程与面向对象,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用不同的方法来实现。

    如果是面向对象的设计思想来解决问题。面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

    可以明显地看出,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了多个步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。 


     面向对象编程三大特性

    在看面向对象编程三大特性之前,先了解一下对象和类的区别。

    对象和类 

    类(Class)是现实或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。类实际上是创建实例的模板。

    对象(Object)是具有类类型的变量。类和对象是面向对象编程技术中的最基本的概念。 而对象就是一个一个具体的实例。

     定义类的方法: 

    class 类():  

              pass

    那么如何将类转换成对象呢?

    实例化是指在面向对象的编程中,把用类创建对象的过程称为实例化。是将一个抽象的概念类,具体到该类实物的过程。实例化过程中一般由类名 对象名 = 类名(参数1,参数2...参数n)构成。

    定义类之后一般会用到构造方法__init__与其他普通方法不同的地方在于,当一个对象被创建后,会立即调用构造方法(也称为魔术方法)。自动执行构造方法里面的内容。

     1.封装特性

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。 所以,在使用面向对象的封装特性时,需要:

    1. 将内容封装到某处
    2. 从某处调用被封装的内容,调用方法如下:
    • 通过对象直接调用被封装的内容: 对象.属性名
    • 通过self间接调用被封装的内容:  self.属性名
    • 通过self间接调用被封装的内容:    self.方法名()

    对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过 对象直接或者self间接获取被封装的内容。 

    具体例子如下:

    # 1). 类的定义
    class People:
        # 构造方法(魔术方法): 当创建对象时会自动调用并执行;
        # self实质上是实例化出来的对象, e.g: xiaoming, xiaohong;
        def __init__(self, name, age, gender):
            # print("正在创建对象")
            # print(self) # 实质上是一个对象
            # 将创建对象的属性(name, age, gender)封装到self(就是实例化的对象)变量里面;
            # 在类里面定义的变量: 属性
            self.name = name
            self.age = age
            self.gender = gender
        # 在类里面定义的函数: 方法
        def eat(self):
            print('%s eating......' %(self.name))
    
        def sleep(self):
            # 获取对象self封装的属性(name, age, gender)
            print('%s sleep.......' %(self.name))
    
    # 2). 实例化: 通过类实现对象的创建
    xiaoming = People("小明", 20, '男')
    # 将对象self/xiaoming封装的属性(name, age, gender)从里面拿出来;
    print(xiaoming.name)
    xiaoming.eat()
    xiaoming.sleep()
    
    xiaohong = People("小红", 20, '女')
    print(xiaohong.name)
    xiaohong.eat()
    xiaohong.sleep()

     2.继承特性

     1)继承

    继承描述的是事物之间的所属关系,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类、扩展类(Subclass),而被继承的class称为基类、父类或超类(Baseclass、Superclass)。

    问题一:如何实现继承呢?         

    子类在继承的时候,在定义类时,小括号()中为父类的名字,例如: class son(father):   这里father就是son的父类。    

    问题二:继承的工作机制是什么?             

    父类的属性、方法,会被继承给子类。 举例如下:如果子类没有定义__init__方法,父类有,那么在子类继承父类的时候这个方法就被继承了,所以只要创建对象,就默认执行了那个继承过来的__init__方法。

    重写父类方法:就是在子类中,有一个和父类相同名字的方法,那么在子类中的方法就会覆盖掉父类中同名的方法,就实现了对父类方法的重写。

    调用父类的方法:

    1. 在子类中,直接利用  父类名.父类的方法名() 
    2. super()方法: python2.2+的功能,格式为: super(子类名称, self).父类的方法名() (建议用此方法)

    2)多继承 

     多继承,即子类有多个父类,并且具有它们的特征。

    新式类与经典类的区别:

    在Python 2及以前的版本中,由任意内置类型派生出的类,都属于“新式类”,都会获得所有“新式类”的特性;反之,即不由任意内置类型派生出的类,则称之为“经典类”。

    新式类:

    class 类名(object):

            pass

    经典类:

    class 类名:

           pass

    “新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。 

    它们两个最明显的区别在于继承搜索的顺序不同,即:    

    经典类多继承搜索顺序(深度优先算法):先深入继承树左侧查找,然后再返回,开始查找右侧。    

    新式类多继承搜索顺序(广度优先算法):先在水平方向查找,然后再向上查找。

    图示如下:

     

    具体例子如下:

    # python2:
        # 经典类: 	class Father:
        # 新式类:   class Father(object):
    # python3:
    #       所有的都是新式类
    
    # 新式类:  广度优先
    # 经典类:  深度优先
    class D:
    	a = 'd'
    
    class B(D):
    	pass
    
    class C(D):
    	a = 'c'
    
    class A(B, C):
    	pass
    obj = A()
    print(obj.a)

    运行结果是 c,由此可见为广度优先搜索的结果。

    3)私有属性与私有方法

    默认情况下,属性在 Python 中都是“public”, 大多数 OO (面向对象)语言提供“访问控制符”来限定成员函数的访问。 

    在 Python 中,实例的变量名如果以 __ (双下划线)开头,就变成了一个私有变量/属性(private),实例的函数名如果以 __ 开头,就变成了一个私有函数/方法(private)只有内部可以访问,外部不能访问。

    那么私有属性一定不能从外部访问吗?

    python2版本不能直接访问 __属性名,是因为 Python 解释器对外把  __属性名 改成了  _类名__属性名 ,所以,仍然可以通过 _类名__属性名  来访问 __属性名 。 但是不同版本的 Python 解释器可能会把 __属性名  改成不同的变量名,因此不建议用此类方法访问私有属性。 

    私有属性和方法的优势:

    1. 确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。      
    2. 如果有要允许外部代码修改属性怎么办?可以给类增加专门设置属性方法。 为什么大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数。

    具体实例如下:

    class Student(object):
        __country = 'china'
        def __init__(self, name, age, score):
            self.name = name
            # 年龄和分数是私有属性
            self.__age = age
            self.__score = score
    
        # 私有方法, 只能在类内部执行;
        def __modify_score(self, scores):
            self.__score = scores
            print(self.__score)
    
        def set_age(self, age):
            if 0<age <150:
                self.__age = age
                print("当前年龄:", self.__age)
            else:
                raise  Exception("年龄错误")
    
        def set_score(self, scores):
            if len(scores) == 3:
                self.__score = scores
            else:
                raise Exception("成绩异常")
    class MathStudent(Student):
        pass
    
    student = Student("Tom", 10, [100, 100, 100])
    # 在类的外部是不能直接访问的;
    print(student.name)
    
    student.set_age(15)
    # Python 解释器对外把  __属性名 改成了  _类名__属性名
    # print(student._Student__age)

    3.多态特性 

    多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。通俗来说: 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。

    多态的好处就是,当我们需要传入更多的子类,只需要继承父类就可以了,而方法既可以直接不重写(即使用父类的),也可以重写一个特有的。这就是多态的意思。调用方只管调用,不管细节,而当我们新增一种的子类时,只要确保新方法编写正确,而不用管原来的代码。这就是著名的“开放封闭”原则: 

    • 对扩展开放(Open for extension):允许子类重写方法函数    
    • 对修改封闭(Closed for modification):不重写,直接继承父类方法函数

     

    展开全文
  • 面向对象编程(Python版详解)

    千次阅读 多人点赞 2020-04-03 15:28:42
    面向对象编程介绍二.类和对象三.类的构成 一.面向对象编程介绍 如今主流的软件开发思想有两种:一个是面向过程,另一个是面向对象。面向过程出现得较早,典型代表为C语言,开发中小型项目的效率很高,但是很难适用...
  • 面向对象编程

    2020-10-10 12:42:25
    面向对象编程是一种编程方式,该编程方式需要靠类和对象实现,所以面向对象编程就是类和对象的实现。 类:就是一个模板,一个模板里面有很多函数,函数有很多功能。就相当于我们用的ppt一样,不同的ppt有不同的模板...
  • 面向对象编程,再见!

    千次阅读 多人点赞 2018-10-14 11:36:56
    作为程序员,你是使用函数式编程还是面向对象编程方式?在本文中,拥有 10 多年软件开发经验的作者从面向对象编程的三大特性——继承、封装、多态三大角度提出了自己的疑问,并深刻表示是时候和面向对象编程说再见了...
  • 面向对象编程基本概念

    千次阅读 2018-04-18 16:19:24
    面向对象编程(OOP)为软件社区引入了一场革命,以帮助解决这些问题。 OOP专注于模块化,改变容忍度,代码重用,易于理解和分布式开发。今天大多数项目都使用面向对象的概念。由于C ++引入了OOP,因此用户体验已经...
  • C 语言实现面向对象编程

    万次阅读 多人点赞 2018-08-14 19:13:32
    面向对象编程(OOP)并不是一种特定的语言或者工具,它只是一种设计方法、设计思想。它表现出来的三个最基本的特性就是封装、继承与多态。很多面向对象的编程语言已经包含这三个特性了,例如 Smalltalk、C++、Java。...
  • 在计算机科学中,对象(英语:object),台湾译作物件,是一个存储器地址,...是面向对象(Object Oriented)中的术语,既表示客观世界问题空间(Namespace)中的某个具体的事物,又表示软件系统解空间中的基本元素。
  • 《C#面向对象程序设计》教案完结篇发布

    万次阅读 多人点赞 2011-06-18 14:55:00
    《C#面向对象程序设计》教案完结篇发布 《C#面向对象程序设计》是我为零面向对象编程基础的学生所设计的教案,共9讲,循序渐进地介绍了在.NET平台开发桌面应用程序所必须掌握的面向对象基础知识,能引导学生迈入...
  • 总体上来说,是先构建一个主过程来启动程序流程,随后根据程序走向来调用相关的其他过程,这种程序设计思想被称为结构化编程。结构化编程乍一看是面向最终结果,实际上是完全针对运行过程进行编程,要求程序员具有...
  • 今天,我们以一个例子(如打扫房间)来说明面向过程和面向对象程序流程上的不同之处。在菜鸟分析看来:面向过程就是将编程当成是做一件事,要按步骤完成,每一步就是一个过程。比如菜鸟分析要打扫房间这件事,需要...
  • C++面向对象程序设计50道编程题(第01题)

    万次阅读 多人点赞 2018-11-28 12:57:02
    C++面向对象程序设计50道编程题(第01题) 摘要:C++程序设计实习是为学生提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机的结合起来,锻炼学生的分析问题和解决问题的能力,提高学生运用所...
  • 什么是面向对象编程思想?

    万次阅读 2017-05-16 09:44:11
    面向对象编程产生的历史原因:由于面向过程编程在构造系统时,无法解决重用,维护,扩展的问题,而且逻辑过于复杂,代码晦涩难懂,因此,人们开始想能不能让计算机直接模拟现实的环境,以人类解决问题的方法,思路...
  • 从面向过程到面向对象

    万次阅读 2015-06-03 13:38:20
    在这期间,程序设计语言主要经历了从面向过程(如 C 和 Pascal 语言)到面向对象(如:C++、Java、Objective-C),再到面向组件编程(如 .NET 平台下的 C# 语言),以及正在快速发展的面向服务架构技术(如 SOA 和 ...
  • 面向过程编程 面向过程编程是一种以过程为中心的编程思想,分析出解决问题的步骤,然后用函数把这些...面向对象编程是将事物对象化,通过与对象进行通信来解决问题。面向对象编程,数据和对数据的操作是绑定在一起的。
  • Smalltalk语言

    万次阅读 2015-05-19 16:56:48
    Smalltalk被公认为历史上第二个面向对象的程序设计语言和第一个真正的集成开发环境 (IDE)。 Smalltalk对其它众多的程序设计...Smalltalk编程语言对近代面向对象编程语言影响很大,所以称之为“面向对象编程之母”。
  • 面向对象编程的三大特征简述

    千次阅读 2019-02-26 17:47:34
    面向对象编程的三大特性,简要阐述如下 (1).继承: 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继 承...
  • 上午单位的C++大佬给我们分享了一些编程思想,开始介绍了面向对象和面向过程 面向过程是什么,就是对事件的过程进行编程,我们已知事件的发展过程,我们根据过程发展的节点去编程。整个编程是过程驱动,开始,然后...
1 2 3 4 5 ... 20
收藏数 686,162
精华内容 274,464
关键字:

面向对象编程