精华内容
下载资源
问答
  • java面向对象

    万次阅读 多人点赞 2018-08-21 16:51:59
    包括面向对象概念、类与对象的关系、封装、构造函数、this关键字、static关键字、单例设计模式、继承、多态、内部类、异常、包等java基础知识。 1、面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是...

    本文内容是根据毕晓东老师的视频教程总结而得。包括面向对象概念、类与对象的关系、封装、构造函数、this关键字、static关键字、单例设计模式、继承、多态、内部类、异常、包等java基础知识。

    1、面向对象

    • 面向对象是相对面向过程而言
    • 面向对象和面向过程都是一种思想
    • 面向过程强调的是功能、行为
    • 面向对象:将功能封装进对象,强调具备了功能的对象
    • 面向对象是基于面向过程的

    面向过程例子:

    把大象放进冰箱里分为以下步骤:把冰箱门打开;把大象放进去;关上冰箱门(强调过程和过程中所涉及的行为(强调行为、动作、过程))。

    用面向对象思想考虑:无论是打开冰箱,放进大象,关闭冰箱,所有操作都是操作冰箱这个对象,所以只需要将所有功能都定义在冰箱这个对象上,冰箱上就有打开、存储、关闭得所有功能 。      

    由上可知,面向对象是一种思想,能让复杂问题简单化,程序员不需要了解具体的实现过程,只需要指挥对象去实现功能。例,面试官面试面试者就是面向对象的体现,面试官需要找具有编程功能的对象(面试者),而我就是一个具有编程功能的对象,面试完后,让面试者去编程,面试者就去实现编程功能。

    面向过程和面向对象图示:

    2、类与对象的关系

    面向对象三大基本特征:封装、继承、多态。而面向对象的过程就是找对象、建立对象、使用对象、维护对象的关系的过程。

    2.1类和对象的关系:

    类:是对现实生活中事物的描述。

    对象:就是这类事物,实实在在存在的个体。

    如现实生活中的对象:张三、李四。想要描述对象张三和李四,就需要提取对象中的共性内容。即对具体对象的共性的抽取。在描述时,这些对象的共性有:姓名、性别、年龄、学习java功能。而每个学员又有自己独有的姓名、性别、年龄、学习方式。

    在java中,描述是用类的方式实现,而类是通过new操作符所产生的实体来实现,而这个实体在堆内存中再映射到java中去。简单的说,描述就是class定义的类,具体对象就是对应java在堆内存中用new建立的实体

    描述事物其实就是在描述事物的属性和行为(方法),属性对应的是类中的变量,行为对应的是类中的函数(方法)。其实定义类,就是在描述事物,就是在定义属性和行为,属性和行为共同成为类中的成员(成员变量和成员方法)。

    示例:描述汽车。

    package com.vnb.javabase;
    public class Car {
       //描述颜色
       String color="red";
       //描述轮胎数
       int num = 4;
       //运行行为
       void run(){
          System.out.println("color:"+color+";  轮胎数:"+num);
       }
    }
    
    class CarDemo{
       public static void main(String[] args) {
          //生产汽车。在java中通过new操作符来完成,其实就是在堆内存中产生一个实体
          //car引用型变量(句柄),car就是一个类类型变量。类类型变量指向对象(该类产生的实体)
          //堆内存中有默认初始化值(color=null);而"red"称为显示初始化值;
          Car car = new Car();
    
          //需求:将已有车的颜色改为蓝色,指挥该对象做使用。在java中指挥方式是,对象.对象成员
          car.color="blue";
    
          //让车行驶起来
          car.run();
       }
    }

    生产汽车类在内存中的图示及解析:

    如上图,首先在栈内存中有一个Car c;然后在堆内存中new Car(),默认初始化color为null,num为0;再将color设置显示初始化值为”red”,将num设置显示初始化值为4;将new Car()产生的地址值0x0099赋给栈内存,再由栈指向堆中的0x0099的地址。

    生产两辆车(建立多个对象)在内存中的图示及解析:

    如上图所示,建立多个对象的过程:首先在栈中初始化c,通过new Car()方式在堆中建立Car对象,初始化color为null,num为0,再将color赋值为”red”,将num赋值为4。将new Car()产生的地址值0x0099赋给栈内存,再由栈指向堆中的0x0099的地址。

    在栈中初始化C1,通过new Car()方式在堆中建立Car对象,初始化color为null,num为0,再将color赋值为”red”,将num赋值为4。将new Car()产生的地址值0x0045赋给栈内存,再由栈指向堆中的0x0045的地址。

    此处产生的是两个对象对应的两个地址值。

    多个引用指向同一个对象的图示及解析:

    如上图所示,首先在栈中初始化c,通过new Car()方式在堆中建立Car对象,初始化color为null,num为0,再将color设置显示初始化值为”red”,将num设置显示初始化值为4。将new Car()产生的地址值0x0078赋给c的栈内存,再由栈指向堆中的0x0078的地址。再将堆中num的值改为5(因为成员变量在堆内存中);

    建立第二个引用时,首先在栈中初始化c1,然后将c的地址值0x0078赋给c1,并且c1指向堆中的0x0078所引用的对象,再将堆中的对象的color改为green。由此,无论在c还是c1引用上修改值后,指向的都是堆内存中的对象地址值0x0078。所以打印出的值为:5,green。

    2.2成员变量和局部变量的区别:

    作用范围:成员变量作用于整个类中。局部变量作用于方法中或者语句中。

    在内存中的位置:成员变量在堆内存中,因为对象的存在,才在内存中存在;局部变量存在栈内存中。

    2.3匿名对象:

    匿名对象是对象的简化形式。有两种使用情况:当对对象方法仅进行一次调用时;匿名对象可以作为实际参数进行传递

    例如:

    Car c = new Car();

    c.num = 5;

    可简化为:new Car().num = 5;

                      new Car().color = “red”;

                      new Car().run();

    匿名对象和非匿名对象在内存中存储方式区别:

    如上图,匿名对象和非匿名对象区别(注:匿名对象在栈中无数据)。使用匿名对象时,当new Car().num = 5;执行完后创建的对象就成为垃圾;new Car().color = “red”执行完后,此对象也会成为垃圾,因此匿名对象调用属性是没有意义的。但是,new Car().run()有意义。

    综上所述,匿名对象调用属性无意义,调用方法有意义

    匿名对象的两种使用方式:

    • 匿名对象使用方式一:当对对象的方法只调用一次时,可以用匿名对象来完成,这样比较简化;但是,如果对一个对象进行多个成员调用,必须给这个对象起名字。例如:

    Car c =  new Car();

    c.run();

    c.num=4;

    new Car().run();

    • 匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。例如:

    需求:汽车修配厂,对汽车进行改装,将来的车都改成黑色且只有三个轮胎。

    main(){

     Car c = new Car();

     show(c);

    }

    public static void show(Car c){

    c.num = 3;

    c.color = “black”;

    c.run();

    }

    上例的内存图示及解析:

    执行main方法后,首先会再栈内存中有一个Car c的引用,然后会在堆内存中new一个Car对象,生成对应的地址值0x0034;当执行show()方法时,会在show方法中再建立一个引用c(注意连个引用不同),再将main方法中c的地址值通过匿名类参数形式传递给show()方法,因此两个引用指向的是同一个地址0x0034。匿名对象传入show()方法时,当show方法执行完后,栈中show()指向的内存空间将会成为垃圾,其对应指向的对象地址和对象也成为垃圾。

    所以就有了使用java程序写缓存机制:用java定义空间存储缓存型的数据,需要的时候就用,不需要的时候就不用。此时需保证其的生命周期,不指定则虚拟机会直接回收,而虚拟机回收垃圾是不定时的,且有些对象不会回收。所以写缓存的时候,在释放对象空间时,必须考虑对象的强引用、弱引用、软引用、虚引用。

    3、封装

    封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。(在使用对象时,没有必要知道对象内容是如何完成对应功能的,我们只需要指挥对象去执行即可)。

    封装的好处:将变化隔离(内部功能细节变化不影响使用);便于使用(不用了解内部的具体实现);提高重用性;提高安全性(只对外暴露一些简单的内容供使用)。

    封装的原则:将不需要对外提供的内容都隐藏起来;把属性都隐藏起来,只提供公共方法对其访问。

    函数本身就是java代码中的最简单的封装体。也是封装体,类中方法不一定全部暴露出去,可通过权限修饰符进行隐藏。也是封装体,如框架,拿来即用。

    函数封装体:

    封装具体示例:

    如上图,当p.age=-20时,就会出现安全隐患,人的年龄不可能为负数,所以可以使用修饰符进行控制权限。使用private int age;私有化后,类以外即使建立了对象也不能再直接访问该属性。但是属性或方法一旦私有了,就需要对外提供访问方式(即提供getter和setter方法等操作)。因此需要给这个人的年龄提供对外访问方式。

    之所以对外提供访问方式,是因为可以在这种访问方式中加入逻辑判断等语句,对访问的数据进行操作。提高代码的健壮性。如下例所示:

     在设置人的年龄时,set方法中需要满足条件,才可继续执行,否则提示非法。

    该示例在内存中表示,如下图:

    执行main()方法后,在栈内存中产生了一个p的引用,然后在堆内存中建立Person对象,并分配内存空间0x0012,并将这个地址值赋给p引用,然后由p再指向Person对象中的这个地址0x0012。new Person对象,执行到private int age时,在堆内存(成员变量在堆内存中分配空间)中产生了一个age,并有了默认初始化值0。当p引用设置年龄为40时(p.setAge(40)),会通过setAge()方法中的this.age = a(this即代表p引用)将堆中的age值改为40。当执行p.speak()时,拿到成员变量age的值40并输出(成员变量age由局部(setAge())接收进来并改变其值后,其他方法(speak())也可以用(拿到的还是setAge()执行后的40))。

    私有仅仅是封装的一种表现形式,只要权限在别人访问不到的范围都是封装。

     

    4、构造函数

    构造函数特点:

    • 函数名与类名相同
    • 不用定义返回值类型
    • 不可以写return语句

    作用:给对象进行初始化。

    构造函数示例:

    构造函数对象一建立就会调用与之对应的构造函数,可用于给对象进行初始化。当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数,当自己定义了构造函数后,默认的空构造函数就不存在了。

    注意:默认构造函数的特点;多个构造函数是以重载的形式存在的

    多个构造函数以重载形式存在的示例:

    构造代码块:

    在构造代码块中,对象一建立就立即运行,而且优先于构造函数执行。构造代码块中定义的是不同对象具有共性的初始化内容

    构造代码块和构造函数的区别:构造代码块是给所有对象进行统一初始化;而构造函数是给对应的对象初始化。

    5、this关键字

    5.1this关键字的基本阐述

    如上图,发现Person(String a)构造函数中,a变量是无意义的,不能见名知意。因此将a改成name表示姓名,即局部变量和成员变量名称相同。但如下图,发现执行结果name并没有赋值成功:

     

    因此如何区分局部和成员变量?即使用this关键字。

    如上图,this关键字看上去,是用于区分局部变量和成员变量同名情况。其实,this代表本类的对象。

    那么this到底代表哪一个对象?如下图:

    this代表它所在函数所属对象的引用。简单的说,哪个对象在调用this所在的函数,this就代表哪个对象。例如,当执行到Person p = new Person("lisi");时,建立Person对象,执行到Person对象的构造函数Person(String name)后,此时的this代表的是p引用。而当代码执行到Person p1 = new Person("zhangsan");时,执行到Person对象的构造函数Person(String name)后,this代表的是p1引用。

    5.2this关键字的应用:

    需求:给人定义一个判断是否是同龄人的功能。

    如上图,this和p1的地址值是指向同一个对象。当执行到boolean b = p1.compare(p2);时,会调用到compare(Person p)方法,此时,p2会以参数形式传给compare()方法,而由于是由p1调用的compare()方法,所以p1引用即当前对象this引用。即his和p1的地址值是指向同一个对象。

    this的应用:当定义类中方法时,该方法内部要用到调用该方法的对象时,这时用this表示这个对象。但凡本类功能内部使用到了本类对象,都用this表示。

    5.3this关键字在构造函数中的应用:构造函数间调用,只能使用this进行互相调用,this函数不能用在一般函数间

    this(name);对Person对象进行姓名初始化,this代表本对象。this.name = name是将值传递过去。

    this语句(不是this关键字)只能定义在构造函数的第一行。如下图:

    初始化动作要先执行,如先执行this(name)必须在this.name=name前才行。

    6、static关键字

    6.1概述

    static关键字:用于修饰成员(成员变量和成员函数)

    被修饰后的成员具备以下特点:

    • 随着类的加载而加载(类一加载到内存中时,静态static就已经加载到内存空间(方法区)中,反之随着类的消失而消失,说明它的生命周期最长)
    • 优先于对象存在(静态是先存在的,对象是后存在的)
    • 被所有对象所共享
    • 可以直接被类名调用

    使用注意:

    • 静态方法只能访问静态成员
    • 静态方法中不可以写this,super关键字
    • 主函数是静态的

    6.2为什么要使用静态static关键字?

    如以上两图所示,创建了两个对象引用P和P1,如果只在中国范围内,而不使用静态关键字static,则需要在堆内存中开辟两个country=”cn”空间(多个空间存在共同数据),那么对象创建得越多占用的内存就越多,如下图,将country=”cn”定义成静态的,则只需要在方法区中定义一次即可(static String country = “CN”),如下图:

    方法区(共享区、数据区):存放共享数据,方法及方法体等内容。

    当成员(包括成员变量和方法)被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用。格式:类名.成员。

    静态static优先于对象的存在,即静态会随着类的加载而加载,消失而消失(说明生命周期最长)。静态的成员变量也叫类变量,非静态的成员变量也叫实例变量。

    6.3为什么不把所有的成员都定义为静态static?

    要区分什么数据是对象特有的,什么数据是多个对象共享的,这样才符合生活中的描述;对象在被用完后会被回收,但是静态static的数据生命周期特别长,用完后还会一直存在,因此会存在垃圾

    6.4实例变量和类变量的区别

    • 存放位置:类变量(静态成员变量)随着类的加载而存在于方法区中;实例变量随着对象的建立而存在于堆内存中
    • 生命周期:类变量生命周期最长,随着类的消失而消失;实例变量生命周期随着对象的消失而消失。

    6.5静态的使用注意事项

    • 静态方法只能访问静态成员(成员变量和方法),非静态方法既可以访问静态成员也可以访问非静态成员

    • 静态方法中不可以定义this,super关键字。因为静态优先于对象存在

    如下图,this.name不可用,this代表对象,而静态方法优先于对象创建,在执行静态方法show()时,对象Person还未创建,所以此时this 还未初始化过,所以不可用。

    6.6静态有利有弊

    利:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中存储一份;可以直接被类名调用。

    弊:生命周期过长(可能会有垃圾不能被回收);访问出现局限性(静态虽好,但只能访问静态)。

    6.7主函数中的静态

    主函数是静态的:主函数是一个特殊的函数,作为程序的入口,可以直接被JVM调用。

    主函数的定义:

    • public:代表着该函数访问权限是最大的
    • static:代表主函数随着类的加载就已经存在了
    • void:代表主函数没有具体的返回值返给虚拟机JVM
    • main:不是关键字,但是是一个特殊的单词,可以被JVM识别,且是主函数特有的。
    • String[] args: 函数的参数,参数类型是一个数组,该数组中的元素是字符串,字符串类型的数组。

    主函数是固定格式的:JVM识别

    public static void main(int x){}也可以写(主函数被重载),但是JVM会优先从public static void main(String[] args){}开始执行。JVM在调用主函数时,传入的是 new String[0],作用:可以往参数里传入数据,在主函数里就可以拿到参数。

    传递参数给主函数并由主函数获取:

    • 使用命令传: java 类名 参数

    • 通过另一个类的主函数传值,然后由测试类主函数进行获取:

    6.8什么时候使用静态?

    要从两个方面下手:因为静态修饰的内容包括成员变量和成员函数。

    什么时候定义静态变量(类变量)?

    当对象中出现共享数据时,该数据需要被静态所修饰;而对象中的特有数据要定义成非静态存在堆内存中。

    6.9什么时候定义静态函数?

    当功能内部没有访问到非静态数据(对象的特有数据(非静态成员变量))时,该功能可以定义成静态的。

    例:对象是为了封装数据的,但是下例中对象里的特有数据name并没有使用到,所以show()方法可以使用静态。

    class Person{
    String name;
    public static void show(){
      System.out.println(“haha”);
    
    }
    
    public static void main(String[] args){
        Person.show();
       }
    }

    但是下例中有使用到对象中的非静态成员name,所以show()方法绝对不能使用静态:

    class Person{
    String name;
    public static void show(){
      System.out.println(name+“haha”);//因为静态先于对象存在,在创建静态方法show时,对象Person还不存在,所以name也不存在
    }
    
    public static void main(String[] args){
     Person p = new Person();
     p.show();
    }
    }

    6.10静态的应用—工具类

    如上图,一个获取数组中最大值的类。可以发现,如果有很多类,都需要使用到获取数组最大值这个方法时,每个类都需要写一遍这些代码,因此可以将获取数组最大值的代码统一封装到一个静态工具类中,需要使用时调用即可。如下图所示:

    因此,静态工具类即将每一个应用程序中都有共性的功能,进行抽取,独立封装,以便复用。

    原始的ArrayTool.java类:

    package com.vnb.javabase;
    /**
     * 
     * Description:数组工具类
     * @author li.mf
     * @date 2018年8月15日
     *
     */
    public class ArrayTool {
    
    	/**
    	 * 获取数组最大值
    	 * @param arr
    	 * @return
    	 */
    	public int getMax(int[] arr){
    	
    		int max = 0;
    		for (int i = 1; i < arr.length; i++) {
    			if(arr[max]<arr[i]){
    				max = i;
    			}
    		}
    		return arr[max];
    	}
    	
    	/**
    	 * 获取数组最小值
    	 * @param arr
    	 * @return
    	 */
    	public int getMin(int[] arr){
    		
    		int min = 0;
    		for (int i = 1; i < arr.length; i++) {
    			if(arr[min]>arr[i]){
    				min = i;
    			}
    		}
    		return arr[min];
    	}
    	/**
    	 * 选择排序
    	 * @param arr
    	 */
    	public void selectSort(int[] arr){
    		for (int i = 0; i < arr.length-1; i++) {
    			for (int j = i+1; j < arr.length; j++) {
    				if(arr[i]>arr[j]){
    					swap(arr,i,j);
    				}
    			}
    		}
    		
    	}
    	/**
    	 * 冒泡排序
    	 * @param arr
    	 */
    	public void bubbleSort(int[] arr){
    		for (int i = 0; i < arr.length; i++) {
    			for (int j = 0; j < arr.length-i-1; j++) {
    				if(arr[j]>arr[j+1]){
    					swap(arr,j,j+1);
    				}
    			}
    		}
    		
    	}
    	
    	public void swap(int[] arr,int a,int b){
    		int temp = arr[a];
    		arr[a] = arr[b];
    		arr[b] = temp;
    	}
    	
    	public void printArray(int[] arr){
    		System.out.print("{");
    		for (int i = 0; i < arr.length; i++) {
    			if(i!=arr.length-1){
    				System.out.print(arr[i]+",");
    			}else{
    				System.out.print(arr[i]+"}");
    			}
    		}
    	}
    }
    

    数组工具类的测试类ArrayToolTest.java:

    package com.vnb.javabase;
    
    public class ArrayToolTest {
    
    	public static void main(String[] args) {
    
    		int[] arr = {1,2,6,8,3};
    		
    		ArrayTool arrayTool = new ArrayTool();
    		int max = arrayTool.getMax(arr);
    		System.out.println("最大值为:"+max);
    		
    		int min = arrayTool.getMin(arr);
    		System.out.println("最小值为:"+min);
    		
    		arrayTool.printArray(arr);
    		arrayTool.selectSort(arr);
    		arrayTool.printArray(arr);
    	}
    }
    

    由例可见,ArrayTool类都没有用到ArrayTool中特有的数据(非静态的成员变量),都是由用户传参的arr进去,所以可以写成static。虽然可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作。但是,对象是用于封装数据的,而ArrayTool对象并未封装特有数据;操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。所以,这时就可以考虑,让程序更严谨而不需要对象。可以将ArrayTool中的方法都定义成static的,直接通过类名调用即可。

    ArrayTool.java中所有方法写成静态,以便调用:

    package com.vnb.javabase;
    /**
     * 
     * Description:数组工具类
     * @author li.mf
     * @date 2018年8月15日
     *
     */
    public class ArrayTool {
    
    	/**
    	 * 获取数组最大值
    	 * @param arr
    	 * @return
    	 */
    	public static int getMax(int[] arr){
    	
    		int max = 0;
    		for (int i = 1; i < arr.length; i++) {
    			if(arr[max]<arr[i]){
    				max = i;
    			}
    		}
    		return arr[max];
    	}
    	
    	/**
    	 * 获取数组最小值
    	 * @param arr
    	 * @return
    	 */
    	public static int getMin(int[] arr){
    		
    		int min = 0;
    		for (int i = 1; i < arr.length; i++) {
    			if(arr[min]>arr[i]){
    				min = i;
    			}
    		}
    		return arr[min];
    	}
    	/**
    	 * 选择排序
    	 * @param arr
    	 */
    	public static void selectSort(int[] arr){
    		for (int i = 0; i < arr.length-1; i++) {
    			for (int j = i+1; j < arr.length; j++) {
    				if(arr[i]>arr[j]){
    					swap(arr,i,j);
    				}
    			}
    		}
    		
    	}
    	/**
    	 * 冒泡排序
    	 * @param arr
    	 */
    	public static void bubbleSort(int[] arr){
    		for (int i = 0; i < arr.length; i++) {
    			for (int j = 0; j < arr.length-i-1; j++) {
    				if(arr[j]>arr[j+1]){
    					swap(arr,j,j+1);
    				}
    			}
    		}
    		
    	}
    	
    	public static void swap(int[] arr,int a,int b){
    		int temp = arr[a];
    		arr[a] = arr[b];
    		arr[b] = temp;
    	}
    	
    	public static void printArray(int[] arr){
    		System.out.print("{");
    		for (int i = 0; i < arr.length; i++) {
    			if(i!=arr.length-1){
    				System.out.print(arr[i]+",");
    			}else{
    				System.out.print(arr[i]+"}");
    			}
    		}
    	}
    }
    

    ArrayToolTest.java

    package com.vnb.javabase;
    
    public class ArrayToolTest {
    
    	public static void main(String[] args) {
    
    		int[] arr = {1,2,6,8,3};
    		
    		int max = ArrayTool.getMax(arr);
    		System.out.println("最大值为:"+max);
    		
    		int min = ArrayTool.getMin(arr);
    		System.out.println("最小值为:"+min);
    		
    		ArrayTool.printArray(arr);
    		ArrayTool.selectSort(arr);
    		ArrayTool.printArray(arr);
    	}
    }
    

    将方法都写成静态后,可以方便与使用,但是仍然发现问题,即该类还是可以被其他程序建立对象的。所以为了更为严谨,强制该类不可以实例化以建立对象,所以可以考虑通过将构造函数私有化完成(私有构造)。

    package com.vnb.javabase;
    /**
     * 
     * Description:数组工具类
     * @author li.mf
     * @date 2018年8月15日
     *
     */
    public class ArrayTool {
    
    	private ArrayTool(){
    		
    	}
    	/**
    	 * 获取数组最大值
    	 * @param arr
    	 * @return
    	 */
    	public static int getMax(int[] arr){
    	
    		int max = 0;
    		for (int i = 1; i < arr.length; i++) {
    			if(arr[max]<arr[i]){
    				max = i;
    			}
    		}
    		return arr[max];
    	}
    	
    	/**
    	 * 获取数组最小值
    	 * @param arr
    	 * @return
    	 */
    	public static int getMin(int[] arr){
    		
    		int min = 0;
    		for (int i = 1; i < arr.length; i++) {
    			if(arr[min]>arr[i]){
    				min = i;
    			}
    		}
    		return arr[min];
    	}
    	/**
    	 * 选择排序
    	 * @param arr
    	 */
    	public static void selectSort(int[] arr){
    		for (int i = 0; i < arr.length-1; i++) {
    			for (int j = i+1; j < arr.length; j++) {
    				if(arr[i]>arr[j]){
    					swap(arr,i,j);
    				}
    			}
    		}
    		
    	}
    	/**
    	 * 冒泡排序
    	 * @param arr
    	 */
    	public static void bubbleSort(int[] arr){
    		for (int i = 0; i < arr.length; i++) {
    			for (int j = 0; j < arr.length-i-1; j++) {
    				if(arr[j]>arr[j+1]){
    					swap(arr,j,j+1);
    				}
    			}
    		}
    		
    	}
    	
    	private static void swap(int[] arr,int a,int b){
    		int temp = arr[a];
    		arr[a] = arr[b];
    		arr[b] = temp;
    	}
    	
    	public static void printArray(int[] arr){
    		System.out.print("{");
    		for (int i = 0; i < arr.length; i++) {
    			if(i!=arr.length-1){
    				System.out.print(arr[i]+",");
    			}else{
    				System.out.print(arr[i]+"}");
    			}
    		}
    	}
    }
    

    ArrayToolTest.java

    package com.vnb.javabase;
    
    public class ArrayToolTest {
    
    	public static void main(String[] args) {
    
    		int[] arr = {1,2,6,8,3};
    		
    		int max = ArrayTool.getMax(arr);
    		System.out.println("最大值为:"+max);
    		
    		int min = ArrayTool.getMin(arr);
    		System.out.println("最小值为:"+min);
    		
    		ArrayTool.printArray(arr);
    		ArrayTool.selectSort(arr);
    		ArrayTool.printArray(arr);
    	}
    }
    

     

    6.11帮助文档的制作(javadoc)

    如果从别的地方拿来的java文件且不在同一目录下,则执行时会报错:找不到文件。如下图,

    所以可以在dos命令行中设置classpath:set classpath-.i;c:\myclass 。-.i;先在当前目录下找,再C盘指定目录myclass下去找。

    /** */  里面写类的描述信息、开发人、开发时间、版本号等。java通过javadoc.exe程序来进行帮助文档的制作。通过命令可以将帮助文档存放到指定位置:javadoc –d myhelp –author –version ArrayTool.java。(如果无此文件夹,会自动创建)。

    要将一个文件写出帮助文档,需要将类修饰符写为public或者protected 。以供外部读取。

    ArrayTool.java帮助文档的查看:

    从索引页面开始看即可(index.html)。

    帮助文档示例:

    一个类中默认会有一个空参数的构造函数,这个默认的构造函数的权限和所属类一致,如果类被public修饰,那么默认的构造函数也带public修饰,如果没有,默认的空构造也没有。注意:默认的构造函数不是自己写的空构造函数。

    6.12静态代码块

    格式:

    static{
         静态代码块的执行语句
    }

    示例:

    static{
         System.out.println(“asdf”);
    }

    静态代码块特点:静态代码块随着类的加载而执行,且执行一次(类加载完后,执行完了,就已经在内存中了),用于给类进行初始化,且优先于主函数执行。

    静态代码块和主函数执行,示例:

    打印顺序:b c a。

    如上图,想让show方法执行,必须先加载StaticCodeDemo类。

    如上图,该类类变量没有任何实体指向,所以StaticCode类不会进行加载,所以没有打印结果。

    如上图,执行顺序:a c d ; 注:如果想要执行特定的构造函数需要在调用的时候进行指定,如上例new StaticCode(4);指定调用的是StaticCode(int x){}构造方法,而不是空参数的构造方法。

    • a表示静态代码块给初始化;
    • b不会执行,因为还未创建过与之对应的对象(已经指定调用其他的构造方法);
    • c表示构造代码块给对象初始化
    • d表示构造函数给对应对象初始化

    {}表示构造代码块给对象初始化的,所以可以用this

    6.13对象初始化的过程

    对象建立过程:

    当类的主函数入口main()方法执行到Person p = new Person(“zhangsan”,20);时,会有一个p引用加载到栈中:

    1)new Person()时会将Person.class文件从硬盘中通过java的虚拟机JVM加载进内存;

    2)执行静态代码块

    3)并开辟了堆内存空间。(非静态成员变量,如属性:name、age)

    4)初始化动作,构造代码块

    执行结果null,0。

    所以会先有默认初始化null和0,再有显示初始化(成员属性的初始化),如下图:

    再进行构造代码块初始化(此代码中无),再构造函数初始化(赋值zhangsan,20)。

    总结:Person p = new Person(“zhangsan”,20);的执行过程?

    1. 因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中
    2. 执行该类中的static代码块,如果有的话,给Person.class类进行初始化
    3. 在堆内存中开辟空间,分配内存地址
    4. 在堆内存中建立对象的特有属性,并进行默认初始化(对象为null,整数为0)
    5. 对属性进行显示初始化(类中声明成员变量初始化值)
    6. 对对象进行构造代码块初始化
    7. 对对象进行对应的构造函数初始化
    8. 将内存地址值赋给栈内存中的p引用
    9. p引用再指向堆内存中的地址值

    6.14对象调用成员过程

    Person p = new Person(“zhangsan”,20);

    p.setName(“lisi”);

    1)在栈中有main主函数的p引用生成

    2)然后在方法区中初始化Person类的方法(showCountry()、setName()、speak())、方法体、静态变量

    3)在堆中开辟空间

    4)在默认初始化(对象为null,整数为0)

    5)再到堆中new Person(“Zhangsan”,20)

    6)再将地址值0x0023赋给栈,再从栈中指向堆中的地址

    7)setName()在栈中开辟空间,非静态的只要一调用this就会有值(指向),this的引用用于给对象赋值(哪个对象调用就代表哪个对象,这里this代表p),即this为0x0023,即this指向堆中的0x0023,因此 setName中this.name = name一执行时,局部变量name的lisi赋值给了堆内存中的this.name。

    调用过程的内存图示:

    当再创建一个对象p1时,在内存中的调用过程,如下:

    当再创建一个对象p1后,会重新在栈内存中初始化p1引用,然后在堆内存中重新new 一个Person对象,设置默认初始化值,然后设置显示初始化值name为ahah,age为90,并开辟空间设置地址值,并将地址值赋给p1,当setName(“qq”)时,会在栈中开辟一块空间,通过this.name = name将堆内存中的name值设置为qq。

    如上图,静态方法showCountry()方法一被调用,在开辟完空间后,没有找到this关键字,所以showCountry()方法就会所属于Person类,不会再进堆内存。调用showCountry()方法时也会用“类名.showCountry()”执行里面的静态方法。

    成员只有被调用才能用,静态的本类省略了类名.method。非静态对象省略this.方法; 静态省略类名.静态方法。

    7、单例设计模式

    7.1概念

    设计模式: 解决某一类问题最行之有效的方法。java中共有23种设计模式。

    单例模式:解决一个类在内存中只存在一个对象(不能new多个实例)

    想要保证对象唯一:

    1. 为了避免其他程序过多建立该类对象,先要控制禁止其他程序建立该类对象
    2. 为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象
    3. 为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式

    代码实现:

    1. 将构造函数私有化(以控制其他程序建立该类对象)
    2. 在类中创建一个本类对象
    3. 提供一个方法可以获取到该对象(方便其他程序对自定义对象的访问)

    7.2饿汉式单例模式

    package com.vnb.javabase;
    /**
     * 
     * Description:单例模式
     * @author li.mf
     * @date 2018年8月16日
     *
     */
    public class Singleton {
    	
    	private static Singleton instance = new Singleton();
    	
    	private Singleton(){
    		
    	}
    	
    	public static Singleton getInstance(){
    		
    		return instance;
    	}
    }
    
    class SingleDemo{
    	
    	public static void main(String[] args) {
    		Singleton ss = Singleton.getInstance();
    	}
    }
    

    内存中实现过程:

    再获取一次单例,发现获取的实例时一致的。如下图:

    测试是否获取的是同一个实例:

    class SingleDemo{
       public static void main(String[] args) {
          Singleton s1 = Singleton.getInstance();
          Singleton s2 = Singleton.getInstance();
          s1.setNum(20);
          System.out.println("num值为"+s2.getNum());
       }
    }

    结果发现,s2获取的值是s1 set进的值。

    单例模式,对于事物该怎么描述,还怎么描述,当需要将该事物的对象保证在内存中唯一时,就将以上者三步加上即可。

    7.3懒汉式单例模式

    package com.vnb.javabase;
    public class Single {
    	private static Single instance = null;
    	private Single(){	
    	}
    	public static Single getInstance(){
    		if(instance == null){
    			instance = new Single();
    		}
    		return instance;
    	}
    }
    

    对象在被调用时,才进行初始化,就叫做对象的延时加载,也称为懒汉式。

    如下图,Single类进内存时,对象还没有存在,而是只有调用了getInstance方法时,才建立对象。

    懒汉式单例模式在内存中表示:

    开发一般使用饿汉式,因为其简单且安全,且懒汉式当有多个人来调用这个方法时会出现问题。当A执行到if(s==null) 后挂掉了,突然去执行其他程序了,此时其他程序B来判断后new了一个对象,之后A又继续执行了,但是A并不知道B已经创建了对象,所以B又new了一个对象,这样就new了多个对象不唯一了。

    为解决上述问题:可以在方法上加同步锁synchronized

    package com.vnb.javabase;
    public class Single {
    	private static Single instance = null;
    	private Single(){	
    	}
    	public static synchronized Single getInstance(){
    		if(instance == null){
    			instance = new Single();
    		}
    		return instance;
    	}
    }
    

    但是加上同步锁后,每次进getInstance()方法后都要执行同步锁,程序的效率会变低。

    为解决低效率问题:可以使用双重判断形式(多线程时进行讲解),使用同步代码块。如下图。但是此方法代码会较多。所以定义单例时建立使用饿汉式。

    package com.vnb.javabase;
    public class Single {
    	private static Single instance = null;
    	private Single(){	
    	}
    	public static Single getInstance(){
    		if(instance == null){
    			synchronized (Single.class) {
    				if(instance == null){
    					instance = new Single();
    				}
    			}
    		}
    		return instance;
    	}
    }
    

    8、继承

    本节主要内容:继承的概述;继承的特点;super关键字;函数覆盖;子类的实例化过程;final关键字。

    8.1继承的概述

    有以下两个类:

    将学生和工人两个类的共性描述提取出来,单独进行描述,只要让学生和工人与单独描述的这个类有关系,就可以了。

     

    继承的好处:提高了代码的复用性;继承让类与类之间产生了关系,有了这个关系,才有了多态的特性。

    注意:千万不能为了获取其他类的功能,简化代码而继承。必须是类与类之间有所属关系才可以继承。所属关系即 is a。java语言中,只支持单继承,不支持多继承,因为多继承容易带来安全隐患(接口与接口之间可以多继承(因为接口之间没有方法体,方法之间不会冲突))。

    如上图,继承多个类,当多个父类中定义了相同功能,当功能内容不同时,子类对象不知道运行哪个功能,就会出现问题。但是java保留另一种体现形式来完成这种表示,叫接口多实现。

    java支持多层继承。也就是一个继承体系。如下图所示:

    C类也可以使用到A类中的功能。

    如何使用一个继承体系中的功能呢?

    想要使用体系,先查阅体系中父类的描述,因为父类中定义的是该体系中的共性功能,通过了解共性功能,就可以知道该体系的基本功能。也可以基本使用了。在具体调用时,为什么要创建最子类的对象?一是因为有可能父类不能创建对象;二是创建子类对象可以使用更多的功能,包括父类的也包括特有的。简单的一句话:查阅父类功能,创建子类对象使用功能。

    8.2类与类之间关系—聚集关系(组合关系)

    事物之间不一定是继承关系,也有聚集关系 has a,简单的说就是谁里面有谁。

    聚合:球员和球队(球队中有球员)

    组合:事物之间的联系比聚合关系更高,比如,心脏和人;手和人,心脏和手必不可少。

    8.3子父类中变量的特点

    以上当父类子类成员变量相同时,打印的是4,因为子类中的num 即为this.num。要打印父类的变量,使用super.num即可,打印子类的变量直接使用num即可。

    new 子类class文件时,会先加载父类的class文件

    变量:如果子类中出现非私有的同名变量时,子类要访问本类中的变量,用this;子类要访问父类中的同名变量,用super。super的使用和this的使用几乎一致,this代表本类对象的引用;super代表父类对象的引用。

    如上图,num前省略super和this打印结果都是4,原因:子类继承父类,子类也能拿到父类的num 4(相当于子类里有自己的num),所以用子类自己的this能拿到num=4;super是指父类引用,this是指本类引用,由于现在没有父类对象只有子类对象(Zi z = new Zi()),所以现在super和this引用指向的是同一个对象(Zi子类对象)即new Zi(),所以只有一个num=4,即同一个子类对象的num(这就是面向对象的多态即父类引用指向子类对象List list = new ArrayList())。

    8.4子父类中函数的特点—覆盖(重写)

    如上图,若子父类中的方法一致,子类运行就会覆盖了父类中的方法。子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样,这种情况是函数的另一个特性,重写(覆盖)。

    当子类继承了父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类却不一致,这时,就没有必要定义新功能,而是使用覆盖特性,保留父类功能定义,并重新父类内容。这就叫重写,也叫做覆盖。如下图:

    用重写特性提高程序扩展性:

    new的时候只要new NewTel即可,而不需要修改Tel类的任何内容,但是重写时会有代码重复以实现父类原有的功能,所以只要使用super调用原有内容即可。如下图:

    覆盖:子类覆盖父类,必须保证子类权限要大于或等于父类权限,才可以覆盖,且父类不能为private修饰(如果是private修饰,子类都不知道父类有此方法存在),否则编译失败;静态只能覆盖静态(虽然此做法无意义);

    重载和重写的区别:

    • 重载只看同名函数的参数列表;
    • 重写是子父类方法要一模一样包括返回值类型。

    如上图,是不允许存在的。因此重写要求子父类中的方法名和返回值类型必须相同。

    8.5子父类中构造函数的特点—子类实例化过程

    子父类构造函数不能覆盖,因为覆盖必须函数名和返回值等都一模一样,但是构造函数的名字必须和类名一致;子类的构造函数有一句隐示的语句super();如下图:

    在对子类对象进行初始化时,父类构造函数也会运行,是因为子类的构造函数默认第一行有一条隐式的语句super(),super()会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super()。如下图所示:

    如下图,当父类中没有空参数的构造时,系统会报错,所以必须手动指定子类引用父类的哪个非空的构造函数。

    为什么子类一定要访问父类中的构造函数?见下图:

    总结:(如上图)因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问一下父类中的构造函数,如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式进行指定。如上图,在建立子类对象后后去查看父类有没有改变num的值,这里父类已经将num值设置为60,所以子类的num也对应改了,最后打印的z.num即父类中设置的60。

    应用:

    父类已经给name赋过值了,子类继承父类后,直接调用(super(name))父类的方法即可获取到父类中设置的值。

    总结:父类已经定义过的方法属性,子类想要使用,直接通过super即可拿到

    如下图,super()语句必须写在子类构造函数的第一行,因为需要先把父类的数据初始化完成后,再初始化自己的。

    当子类构造函数中写了this()方法后,就不能再用super()了,this和super不能同时存在。此时zi(int x)中的this()会访问本类中的zi()空构造,而zi()构造函数中默认有super()就能调用到父类中的属性和方法。

    结论(子类的实例化过程):子类中所有的构造函数,默认都会访问父类中的空参数的构造函数,因为子类每一个构造函数内的第一行都有一句隐式的super(),当父类中没有空参数的构造函数时,子类必须手动通过super语句或者this语句形式来指定要访问的父类中的构造函数。子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,子类中至少要有一个构造函数会访问父类中的构造函数(没写也会有默认的)。

    this和super为什么不能同时存在?因为this和super都必须存在第一行。

    为什么this和super都必须存在第一行?因为初始化动作必须先做。

    8.6 final关键字

    final关键字:

    • 作为一个修饰符,可以修饰类、函数、变量。
    • 被final修饰的类不可以被继承(继承的弊端,打破了封装性,可以复写掉父类的东西,很多基类就会很不安全,可能会被修改),为了避免被继承,被子类复写功能,在类上写final即可(叫做最终类,最终类是不可以被继承的)。
    • 被final修饰的方法,不可以被复写。

    1. 被final修饰的变量是一个常量,只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。如下图:

    只要在内存中,x和y的值都是固定的,不可以更改。

    当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便阅读,而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有的字母都大写,如果有多个单词组成,单词间通过下划线连接。

    2.内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。

    8.7抽象类

    如上图,发现两个方法都一致,所以需要抽取相同功能。但发现虽然两者都在学习,但是学习内容却不一样。解决:可以进行向上抽取,只抽取功能定义,不抽取功能主体(即抽象类)。对于这种方法,必须使用abstract进行修饰。抽象方法必须定义在抽象类中。如下图:

    抽象:即看不懂的事物。

    抽象类的特点:

    1. 抽象方法一定在抽象类中
    2. 抽象方法和抽象类都必须被abstract关键字修饰
    3. 抽象类不可以用new创建对象,因为调用抽象方法没意义(里面的抽象方法连方法体都没有)
    4. 抽象类中的抽象方法要想被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用,如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

    抽象类和一般类没有太大的不同。只是要注意该如何描述事物就如何描述事物,只不过该事物中出现了一些看不懂的东西。这些不确定的部分也是该事物的功能,需要明确出来,但是无法定义主体。而通过抽象方法来表示。

    • 抽象类比一般类多了抽象方法。就是在类中可以定义抽象方法,也可以不定义抽象方法。
    • 抽象类不可以实例化。
    • 抽象类也可以不定义抽象方法,这样只是为了不让该类创建对象。

    抽象类练习:

    假如我们在开发一个系统时需要对员工进行建模,员工包含3个属性:姓名、工号、工资。经理也是员工,除了含有员工的属性外,另外还有一个奖金属性,请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

    分析:

    员工类:name、id、pay

    经理类:继承了员工并有自己特有的奖金属性bonus

    会有一个抽象员工类,员工属于这一类,经理也属于这一类

    8.8模板方法设计模式:

    需求:获取一段程序运行的时间

    原理:获取程序开始和结束的时间并相减即可。获取本机系统时间:System.currentTimeMillis()获取当前时间的毫秒值,返回当前时间减去1970年1月1日0点0分0秒之间的时间差。

    问题:想获取另一段代码的运行时间。解决:直接子类复写掉getTime方法

    但是发现代码重复性很高。

    解决:可以将需要运行代码提取出来形成另一个方法,子类复写时,只需要复写提取出来的代码即可。如下图:

    但是却发现提取出来的需要运行的代码是不确定的,解决:只要将方法写成抽象方法并由子类继承后进行具体实现即可,且getTime方法不可复写所以使用final进行修饰。如下图:

    当代码完成优化后,就可以解决这类问题,这种方式叫做模板方法设计模式。

    什么是模板方法?

    在定义功能时,功能的一部分是确定的,但是一部分是不确定的,而确定的部分在使用不确定的部分时就将不确定的部分暴露出去,由该类的子类去完成。这样可以提高扩展性和复用性。注意:暴露出去的方法不一定抽象,有时会有默认的实现方式。

    8.9接口

    接口:初期理解,可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式表示。

    接口定义时,格式特点:

    1. 接口中常见定义:常量,抽象方法
    2. 接口中的成员都有固定修饰符(常量:public static final;方法:public abstract)

    总结:接口中的成员(包括成员变量和方法)都是public的

    如下,即使少写了成员上的,interface也会进行默认的补全。

    但是,一般建议写全:

    接口也是不可能创建对象的,因为接口中的方法都是抽象的,而抽象方法需要被子类实现。即子类对接口中的抽象方法全都覆盖后,子类才可以实例化,若子类只是实现了父类,却没有覆盖父类的方法,那么子类仍是一个抽象类。如下图:

    如上图中,实现类Test实现了Inter接口后,覆盖了父类接口中的show()方法。因此Test类才可以被实例化。

    接口可以被类多实现,也是对多继承不支持的转换形式,java不支持多继承,但是支持多实现。如下图:

    java不支持多继承是因为父类当中的方法有重复,多继承会导致子类调用时出现冲突,为什么接口不会出现这种问题?

    因为多实现接口中,接口没有方法主体,实现类在实现时,可以重写方法体,即使出现接口中出现多个相同方法,实现类中一个方法就可以全部重写多个接口中的那些相同方法。如下图所示:

    注意:多个接口的相同方法的返回值必须一致。

    类和接口相互之间的关系:

    • 类与类之间:继承
    • 类与接口之间:实现
    • 接口与接口之间关系:继承关系

    接口与接口之间可以多继承(因为接口之间没有方法体,方法之间不会冲突)。所以java中也存在多继承,只是多继承只存在在接口与接口之间,而不存在与类与类或者类与接口之间。

    接口的特点:

    1. 接口是对外暴露的规则
    2. 接口是程序的功能扩展
    3. 接口可以用来多实现(降低了耦合性)
    4. 类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
    5. 接口与接口之间可以有继承关系

    9、多态

    9.1概念

    多态:可以理解为事物存在的多种体现形态

    人:男人、女人

    动物:猫、狗

    猫 x = new 猫();

    动物 x = new 猫();

    函数也具有多态性:重载和覆盖

    本节主要内容:多态的体现;多态的前提;多态的好处;多态的应用等。

    9.2多态—扩展性

    需求:动物(猫、狗)

    package com.vnb.javabase;
    
    abstract class Animal{
    	
    	abstract void eat();
    }
    
    class Cat extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("吃鱼");		
    	}
    	
    	public void catchMouse(){
    		
    		System.out.println("抓老鼠");
    	}
    }
    
    class Dog extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("啃骨头");		
    	}
    	
    	public void kanJia(){
    		
    		System.out.println("看家");
    	}
    }
    
    public class DuotaiDemo {
    	
    	public static void main(String[] args) {
    		Cat c = new Cat();
    		function(c);
    		function(new Dog());
    	}
    	
    	public static void function(Cat c){
    		c.eat();
    	}
    	public static void function(Dog d){
    		d.eat();
    	}
    }
    

    由例可发现,例中只有继承,如果再要加其他动物,还得写其他动物的类并继承动物类,且还要重写动物的吃方法。

    分析发现,所有动物都具有吃的行为,因为他们都是动物。如下图:

    package com.vnb.javabase;
    
    abstract class Animal{
    	
    	abstract void eat();
    }
    
    class Cat extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("吃鱼");		
    	}
    	
    	public void catchMouse(){
    		
    		System.out.println("抓老鼠");
    	}
    }
    
    class Dog extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("啃骨头");		
    	}
    	
    	public void kanJia(){
    		
    		System.out.println("看家");
    	}
    }
    
    public class DuotaiDemo {
    	
    	public static void main(String[] args) {
    		/*Cat c = new Cat();
    		function(c);
    		function(new Dog());*/
    		Animal a = new Cat();
    		a.eat();
    	}
    	
    	public static void function(Cat c){
    		c.eat();
    	}
    	public static void function(Dog d){
    		d.eat();
    	}
    }
    

    总结:多态的体现:父类的引用指向了自己的子类对象(Animal a = new Cat())。

    父类的引用也可以接收自己的子类对象(提高代码的扩展性:以后也其他的猪、老虎类,只要有这个类继承动物类即可)。所以可以通过动物类,去new其子类(即多态),传入什么动物,便由其自己去调用自己的吃方法。如下图:

    package com.vnb.javabase;
    
    abstract class Animal{
    	
    	abstract void eat();
    }
    
    class Cat extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("吃鱼");		
    	}
    	
    	public void catchMouse(){
    		
    		System.out.println("抓老鼠");
    	}
    }
    
    class Dog extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("啃骨头");		
    	}
    	
    	public void kanJia(){
    		
    		System.out.println("看家");
    	}
    }
    
    public class DuotaiDemo {
    	
    	public static void main(String[] args) {
    		function(new Cat());
    		function(new Dog());
    	}
    	public static void function(Animal a){
    		a.eat();
    	}
    }
    

    多态的好处:大大提高了程序的扩展性

    多态的前提:必须是类与类之间有关系(继承或者实现);通常还有一个前提,存在覆盖。

    多态的弊端:提高了扩展性,但是只能使用父类的引用访问父类的成员(如Animal的eat()方法)。

    9.3多态—转型

    package com.vnb.javabase;
    
    abstract class Animal{
    	
    	abstract void eat();
    }
    
    class Cat extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("吃鱼");		
    	}
    	
    	public void catchMouse(){
    		
    		System.out.println("抓老鼠");
    	}
    }
    
    class Dog extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("啃骨头");		
    	}
    	
    	public void kanJia(){
    		
    		System.out.println("看家");
    	}
    }
    
    public class DuotaiDemo {
    	
    	public static void main(String[] args) {
    		
    		Animal a = new Cat();//引用数据类型的类型提升,也称为向上转型
    	}
    	public static void function(Animal a){
    		a.eat();
    	}
    }
    

    多态:Animal a = new Cat();存在引用数据类型的类型提升,即向上转型。

    如果想要调用猫的特有方法时,要如何操作?

    解决:可以向上转型,也可以向下转型,强制将父类的引用,转成子类类型。如下例:

    Animal a = new Cat();

    a.eat();

    Cat c = (Cat)a;

    a.catchMouse();//调用子类特有方法

    注意:Animal a = new Animal();

    Cat c = (Cat)a;//这里是不能强转的,这里的动物类是不明确到底是哪个动物类的

    千万不要出现以下操作:即将父类对象转成子类类型。能转换的是父类引用指向了自己的子类对象时,该引用可以被提升(运行结果是子类结果),也可以被强转转换(向下转型)

    规律:多态自始至终都是子类对象在变化。

    package com.vnb.javabase;
    
    abstract class Animal{
    	
    	abstract void eat();
    }
    
    class Cat extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("吃鱼");		
    	}
    	
    	public void catchMouse(){
    		
    		System.out.println("抓老鼠");
    	}
    }
    
    class Dog extends Animal{
    
    	@Override
    	void eat() {
          System.out.println("啃骨头");		
    	}
    	
    	public void kanJia(){
    		
    		System.out.println("看家");
    	}
    }
    
    public class DuotaiDemo {
    	
    	public static void main(String[] args) {
    		
    		Animal a = new Cat();//引用数据类型的类型提升,也称为向上转型
    	}
    	public static void function(Animal a){
    		a.eat();
    		if(a instanceof Cat){
    			Cat c = (Cat)a;
    			c.catchMouse();
    		}else if(a instanceof Dog){
    			Dog d = (Dog)a;
    			d.kanJia();
    		}
    	}
    }
    

    a instanceof Cat 判断a是否属于Cat这个引用类型。

    一般只用于传的类型是有限的;或传的类型的该类的所属类型,并对此类型有所使用。

    9.4 多态—示例(应用)

    需求:基础班的学生:学习、睡觉等

    高级班的学生:学习、睡觉等

    可以将这两类事物进行抽取。

    9.5多态中成员的特点

    运行结果:

    在多态中(父类有指向子类对象时)成员函数的特点:

    • 在编译时期,参阅引用型变量(Fu类)所属的类中是否有调用的方法,如果有编译通过,如果没有编译失败;
    • 在运行时期,参阅对象(Zi类)所属的类中是否有调用的方法(静态方法除外)。

    对于Fu f = new Zi();后调用子父类中的方法说明:子父类中都有此方法,使用子类中的方法(子类覆盖了父类方法);子类中没有此方法,调用父类的此方法(子继承父类);Fu类中没有此方法,编译失败。如下图(method3会编译失败):

     多态中,成员变量的特点,如下图:

    输出结果:

    在多态中,成员变量的特点:无论编译还是运行,都参考左边(引用型变量所属的类)(此情况一般只会面试出现)。因为有父类是,会先加载父类去拿num。

    打印结果:(开发一般不会出现这种情况)

    所以静态时不会出现多态中成员函数的特点。

    总结:在多态中,静态成员函数的特点:无论是编译时期还是运行时期,都是参考左边。

    因为静态方法存在方法区中,不需要对象,只需要Fu.method4()即可,看的是引用型对象加载的内容(Fu),而不是对象(Zi),只要父类型引用还在,用的还是父类引用,而不是对象。如下图:

    当调用f.method1()时,f确实执行的是对象,method1()被运行的时候是被对象运行,对象在调用非静态方法时,访问的是对象中的数据;但是静态方法method4()本身不访问对象特有的数据,用类名调用的话,它只看所属引用型(Fu)变量中的数据类型,即静态区中的方法,它不参考右边非静态区的方法。如下图:

    动态静态绑定:

    当method4()方法一进内存,因为是静态方法,就已经被绑定在方法所属的类的引用上(Fu),即method4属于Fu。而静态区上,this是动态的,this指向哪个对象就代表哪个对象。而现在写的是Fu f = new Zi(),f.method1(), new的还是Zi,所以运行的还是子类的方法(动态绑定);当Fu f = new Fu()此时就找的是Fu类上的方法。

    多态总结:

    9.6多态的电脑的主板示例

    需求:电脑运行示例,电脑运行是基于主板

    上图中,主板就可以跑起来了

    但是发现问题:运行一段时间后,想上网,想听音乐,主板没有此功能,因此就需要给主板提供扩展性的功能(原来功能毫无扩展性)。如下图:

    该类在内存中表示:

    为降低网卡声卡等和主板的耦合性,会在主板上留一个槽,并约定这些槽的规则,此后,只要符合这个规则,就可以在主板上运行。而这些插槽即接口的编写。如上图的PCI即设定的某些规则。代码如下图所示:

    PCI p = new NetCard();//接口型引用指向自己的子类对象。

    如上图,网卡声卡等都需要符合规则才能用,所以都需要实现PCI接口。

    9.7多态的扩展示例

    需求:对数据库的操作

    数据是:用户信息

    1. 连接数据库 JDBC Hibernate
    2. 操作数据库 CRUD
    3. 关闭数据库连接

    问题:某天发现JDBC太麻烦,需要使用某种框架进行连接数据库,按照以上方法,就需要修改所有方法。如下图:

    内存中:

    但是发现,主程序也需要改,这样代码耦合性太高,所以需要重新设计代码。

    分析:无论如何连接数据库,最后要的只是CRUD,无论采用哪种方式连接,内部的实现方式仍然相同,所以可以专门定义出数据库连接的规则。如下图,interface接口,事先定义好CRUD的接口。之后再需要使用其它数据库连接方式时,也只需要实现该接口即可。

    由此发现,连接数据库的程序和主程序不再有强的耦合关系。

    9.8 Object类 —equals()

    Object:是所有对象的直接或者间接父类,该类中定义的肯定是所有对象都具备的功能。

    java指定所有对象都具备比较性,都能比较两个对象是否相同。此方法定义在Object中,即equals()方法。

    例如:

    equals()方法比较的是对象的地址值。equals()里的参数不确定,所以使用Object,即可多态实现比较。

    自定义比较方法:

    使用“==”对象不同,数据相同即为真,如下图:

    问题:Demo中已经有了比较的方法equals()(超类Object),就不需要重新比较了(功能一致,可以沿袭父类,写自己特有的功能(复写(覆盖)equals()))。如下图:

    Object中没有定义过num,如果不向下转型,是不能进行编译的。

    问题,当传入的对象不同时,运行时出现不可转换错误。解析:一般是自己的对象和自己比较,不是则直接返回false。如下图:

    输出false。

    9.9Object类—toString()

    java 任意对象都可以通过toString()方法返回字符串,所以类.toString()就可以拿到对象的hash值。而hashCode方法也可以返回对象的hash值。

    图中Demo如何得到?

    一个对象的建立要根据类文件进行建立。一个类文件中包含名称、很多构造函数、一般方法等很多东西,如何获取到某个构造函数,只有这个对象最明确,所以可以通过Class来描述这些class文件,通过  类.getClass() 进行获得。

    类中有Class.getClass()方法,可以通过类.getMethods()获取到类文件中所有的方法。

    10、内部类

    10.1内部类概念

    将一个类定义在另一个类的里面,而里面那个类就称为内部类(内置类、嵌套类)。

    内部类访问特点:内部类可以直接访问外部类中的成员,包括私有成员;而外部类要访问内部类中的成员必须要建立内部类的对象。

    好处:可以直接访问外部类中的成员(包括私有成员),而不用创建对象。

    外部能不能直接访问内部类中的方法(function)?

    分析:inner不是独立存在,而是在Outer中,所以使用inner所在类.inner即可(很少用,因为内部类很可能会被private修饰(当内部类是外部类的成员时))。如下图:

    为什么内部类能直接访问外部类中的内容?

    输出结果为6。

    当内部外部存在变量相同时,优先获取内部变量;

    想拿到4(内部类的变量),使用this.x;想要拿到外部类的x=3,可用Outer.this.x。如下图:

    之所以可以直接访问外部类中的成员是因为内部类中持有了一个外部类的引用,该引用写法是”外部类名.this”。

    10.2静态内部类

    访问格式:

    • 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部对象。格式:外部类名.内部类名  变量名 = 外部类对象.内部类对象(Outer.Inner in = new Outer().new Inner())
    • 当内部类在成员位置上,就可以被成员修饰符所修饰。比如,private:将内部类在外部类中进行封装,Static:内部类就具备了静态的特性。当内部类被静态修饰后,只能直接访问外部类中的静态成员了(外部成员也要用static修饰才行)。修饰出现限制了。如下图:

    修改后:在外部其他类中,如何直接访问static内部类的非静态呢?new Outer.Inner().function();如下图:

    在外部其他类中,如何直接访问static内部类的静态呢?

    new Outer.Inner.function();但是这种方式使用得很少。

    注意当内部类中定义了静态成员,该内部类必须是静态的(static)。如下例:

    即当function()方法被static修饰时,Inner也必须是静态修饰

    当外部类中的静态方法访问内部类时,静态类也必须是静态的。如下图:

    改为以下即可:

    10.3内部类定义原则

    类是用来描述现实中事物的,当描述事物时,事物内部还有事物,该事物就用内部类来描述,因为内部事物在使用外部事物中的内容(成员和函数等)。

    示例:描述人体,在描述心脏时,认为心脏也是一个功能,但是心脏描述比较复杂,有跳动、血液等等众多属性,对于这些属性就得用类进行描述,因为,心脏可以访问人体中其他部分,所以,将心脏定义成内部类最合适(内部类:类中包含另一个类),而且心脏不能直接被外部访问,但是提供外部访问的功能。

    10.4匿名内部类

    只有定义在成员位置上,才能被私有或静态所修饰。内部类可以写在类的任意位置上(成员、局部成员(变量或方法)等)

    如下例,访问规则没变:

    上例已经不能被静态私有修饰,Inner在局部方法里,在这里也不能使用static。局部内部类不能用static修饰,非静态没对象不会运行(必须有调用的地方new Inner().function(),如下)。

    方法中的局部变量,内部类在局部,那么内部类就能访问局部变量?

    修改后:

    有上例可知,

    1. 内部类定义在局部时,不能被成员修饰符修饰;
    2. 可以直接访问外部类中的成员,因为还持有外部类中的引用,但是不可以访问它所在的局部变量,只能访问被final修饰的局部变量

    如上图,方法中的参数也必须是final。

    如何只有一个对象实现多次调用method(),如下图:

    调用method()时a=7进栈,执行完后,会释放掉,再调用method()a =8,所以不会冲突。

    匿名内部类:

    1. 匿名内部类其实就是内部类的简写格式
    2. 定义匿名内部类的前提:内部类必须继承一个类,或者实现接口

    将下列例子简化成匿名内部类:

    简化后:匿名了,没有Inner类了,怎么new对象?如下:

    可以使用 new AbsDemo(){

                      void show();

                    }

    AbsDemo本身是抽象类,不能new,但是可以像下面这样写,在复写掉里面的方法。红框的内容是一个对象,是AbsDemo的子类对象(只有子类才可以复写父类的抽象方法)。

    匿名内部类调用本匿名内部类中的方法:

    1. 总结:匿名内部类的格式,new 父类或者接口(构造函数,可以往其传参){定义子类的内容}
    2. 其实匿名内部类就是一个匿名子类对象,可以理解为带内容的对象

    匿名内部类中也可以有子类特有的方法,不一定是覆盖父类的方法,但是,不可以同时调用show和abc方法(匿名内部类只能调用一次)。如下图:

    但是可以,建立多次匿名对象:

    简化,可以将多个匿名内部类取名(利用多态),如下图:

    d.show()可以是父类的方法,d.abc()不能调用,多态中的父类没有abc()方法。

    注:匿名内部类中定义的方法最好不要超过3个。可读性差。

    匿名内部类练习:

    如上图,Test.function:Test类中有一个静态方法function,.method():function这个方法运算后的结果是一个对象。而且是一个Inter类型的对象。因为是Inter类型的对象,才可以调用method()方法。

    Test.function().method();即等同于:

    Inter in = Test.function();

    in.method();

    什么时候用匿名内部类?

    当使用的方法参数类型是接口时,可以再调用方法时传一个匿名内部类(如AWT匿名监听器等)。如下图:

    若没有父类也没有抽象类或接口,想写个匿名内部类,怎么写?

    使用所有类的父类(Object对象),如下图:

    11、异常

    11.1异常概述

    异常:程序运行时出现不正常情况。

    异常由来:问题也是现实生活中的一个具体事物,也可以通过java的类的形式来进行描述,并封装成对象。异常其实就是java对不正常情况进行描述后的对象体现。

    对于问题的划分:一种是严重的问题;一种是非严重的问题。

    对于严重的,java通过Error类进行描述。对于Error类问题一般不编写针对性的代码进行处理;对于非严重的问题,java通过Exception类进行描述,对于Exception类的问题可以使用针对性的处理方式进行处理。

    无论Error或者是Exception都具有一些共性内容:不正常情况的信息、引发原因等,会向上抽取,抽取出来的即为:

    Throwable

         |--Error

         |--Exception

    API解释:

     

    Error异常:

    Exception异常:

    11.2异常try catch

    java 有内置的异常处理方式,只要有某些异常就会进行处理。java提供了特有的语句处理方式,即

    try{

      需要检测的代码

    }catch(异常类 变量){

      处理异常的代码(处理方式)

    } finally{

      一定会执行的语句

    }

    例如:

    在方法div()中,捕获到异常后封装成new AritchmeticException()后,会抛给main中的有try进行异常捕获newAritchmeticException()异常,捕获到后不会继续往下执行,而是有catch到(Exception e = new ArithmeticException();),再执行catch中的语句。

    对捕获到的异常对象进行常见方法操作:

    • String getMessage()  打印异常信息
    • String toString()  打印异常名及信息
    • void printStackTrace();  异常信息、类名及异常出现位置

    其实JVM默认的异常处理机制,就是在调用printStackTrace方法,打印异常的堆栈的跟踪信息。

    11.3异常声明throws

    编写功能时,不清楚是否调用者会传入正确的参数,所以,可以在功能上通过throws的关键字声明该功能有可能会出现问题。例:

    编译时会出现以下错误:

    但是如果不抛出,编译时不会出现问题,而运行会报错:

    如果一直抛出,直至抛给JVM,则会使用JVM默认的异常处理机制:

    抛异常和捕捉异常是有使用场景的。

    11.4多异常处理

    对多异常的处理:

    • 声明异常时,建议声明更为具体的异常,这样处理得更具体

    • 原则:对方声明几个异常就有几个catch块,不要定义多余的catch块,如果多个catch块中的异常出现继承关系,则父类异常catch块放在最下面。建议在进行catch处理时,catch一定要定义具体的处理方式,不要简单定义依据e.printStackTrace(),也不要简单的书写一条输出语句。做法:用硬盘文件记录异常日志文件。

    也可以抛出父类异常Exception:

    若出现了,意料之外的异常,应该是停止执行,让我们发现问题,进行针对性处理,而不是通过Exception进行。如下图:

    11.5自定义异常

    因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象,所以对这些特有的问题,可以按照java的对问题封装的思想,对本项目中的特有问题进行自定义异常封装。

    需求:在本程序中,对于除数是-1,也视为是错误的无法进行运算。那么就需要对这个问题进行自定义的描述。

    当函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作,要么在内部try catch;要么在函数上声明让调用者处理。一般情况在函数内出现异常,函数上需要声明。

    打印结果:

    发现打印结果中只有异常名称却没有异常信息,因为自定义异常并未定义所属信息,那么如何定义异常信息?

    打印结果:

    问题:发现父类构造函数中有个带message的方法

    父类中已经定义了构造函数接收异常信息,所以就会有变量接收这个信息,子类在继承这个类时,只要new Exception()就能获取到这些信息。类似下例:

    所以,异常类如下:

    总结:因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时将异常信息通过super语句传递给父类,就可以直接通过getMessage()获取异常信息。

    自定义类,根据特有数据定义异常,如异常类名、异常的值等,如下图:

    输出结果:

    自定义异常:必须是自定义类继承Exception类。

    为什么继承Exception:

    异常体系有一个特点,因为异常类和异常对象都需要被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点,只有这个体系中的类和对象才可以被throws和throw操作。只有继承Throwable、Exception、Error,只有在这个体系中才能使用throws和throw进行抛出异常。

    11.5异常—throws和throw的区别

    throws和throw的区别:

    1. throws使用在函数上,throw使用在函数内;
    2. throws后面跟的异常类,可以跟多个,用逗号隔开。throw后面跟的是异常对象(throw new 异常类)

    11.6RuntimeException

    ArithmeticException类构造函数有定义message的方法,可以直接使用这个构造方法打印错误信息:

    打印结果:发现函数内抛了,但是函数上并没有声明过,但是编译通过了。

    但是,当抛Exception时发现有安全隐患,编译时直接报错。

    原因:

    由API可发现ArithmeticException异常类的父类是RuntimeException异常,即运行时异常。该异常很特殊。RuntimeException或者RuntimeException的子类如果在函数内抛出了该异常,函数上可以不用声明异常,编译一样通过。如果在函数上声明了该异常,调用者可以不用进行处理(catch或throws),编译一样通过(如下例)。

    原因:之所以不用再函数上声明是因为不需要让调用者处理,当该异常发生,希望程序直接停止。因为在运行时出现了无法继续运算的情况,希望停止程序后由程序员对代码进行修正。如int x = 3/0,一旦3/0被允许执行了,那么x将无法得到正确的值,因此必须对3/0进行正确处理才行

    示例:

    如上例,发现当name传null时,很容易出现空指针异常,我们再出现name传null时,必须要程序员进行修改才行。因此要让其抛异常才行。而且不能在方法上使用throws,让其抛出去。如下图:

    总结:自定义异常时,如果该异常的发生,无法继续进行运算,就让自定义异常继承RuntimeExcetion。

    所以自定义异常示例可改为:

    输出结果:

    对于异常分两种:

    1. 编译时被检测的异常(javac编译时,发现方法中抛出了非RuntimeException及其子类,而方法上没有标识throws,就会认为有安全隐患。此异常时可处理的,要标识出去,让调用者进行对应的处理;如果函数上标识了throws,函数的调用者也必须进行处理,try或抛);
    2. 编译时不被检测的异常(运行时异常:RuntimeException及其子类)(方法内抛throw,但是方法上不标识throws,它会拿着异常对象去判断是否是运行时异常(e instanceof RuntimeException),如果是,无论标识与否都不管)

    11.7 异常练习(应用)

    需求:毕老师用电脑上课

     

    异常:电脑宕机、电脑蓝屏

    要对问题进行描述,封装成对象

    根据电脑操作状态的不同,导致不同问题的产生。

     

    电脑冒烟了,不能抛出去,因为抛出去了其他老师也处理不了,但是当冒烟出现问题后,讲课进度无法继续,出现了讲课进度无法完成的问题,所以虽然捕捉到的是MaoYanExcetion,但是要把它封装成我的问题再跑出去(讲课无法完成问题)再抛出去

    注意:throw后面不会继续执行,throw是函数结束的标志。

    11.7异常—finally

    finally块的代码无论如何都会执行,通常用于释放资源

    示例:数据库连接(数据库连接有限,一旦占用不释放,其他人就会一直连不上)

    连接数据库;数据库操作(throw new SQLException());关闭数据库(无论操作是否成功一定要关闭资源)

    数据没有存储成功也是异常,SQLException我们处理不了,但是数据没有存储成功是可以处理的(分层思想,模块式开发):

    11.8异常—处理语句其他格式

    以下,因为throw new Exception()语句,已经被catch捕捉处理掉,所以语句正确

    catch是处理异常,如果没有catch就代表异常没有被处理,如果该异常时检测时异常,那么必须声明。

    11.9异常—覆盖时异常的特点

    异常在子父类覆盖中的体现:

    • 子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。

    父类已经有问题了,子类要继承父类的话不能比分类还有问题,只能跑父类或者父类的子类的异常

    有一个子类覆盖父类,继承CException,且Test中传入子类对象:

    这样程序会挂,编译就是失败。

    • 如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集
    • 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常;如果子类发生了异常,就必须要进行try处理,绝对不能抛

     

    10.10异常—练习

    有一个圆形和长方形,都可以获取面积,对于面积如果出现非法的数值,视为获取面积出现问题,问题通过异常来表示。

    基本设计:

     

    当传入负数时,面积为负数,无意义

    之前处理方式:

    会发现正常流程代码和问题处理代码结合比较紧密,阅读性差。异常的产生可以让流程处理代码和问题处理代码分离。

     

    输出:

    如果真的出现问题,一旦为负数,就没意义,不会继续执行,所以直接使用RuntimeException即可,也不用进行标识。主函数中也就不需要catch了

    求圆的面积:写RuntimeException也可以,但是,此名称跟程序意义无关,不能见名知意

    所以还是写自定义异常比较直观:

    11.11异常—总结

    异常:是对问题的描述,将问题进行对象的封装。

    异常体系:

    Throwable

    |--Error

    |--Exception

       |--RuntimeException

    异常体系的特点:异常体系中的所有类以及建立的对象都具备可抛性,也就是说可以被throw和throws关键字所操作。只有异常体系具备这个特点。

    throw和throws的用法:

    throw定义在函数内,用于抛出异常对象,throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。

    当函数内容有throw抛出异常对象,并未进行try处理。必须在函数上声明,否则编译失败。注意RuntimeException除外。也就是说,如果函数内抛出的是RuntimeException异常,函数上可以不用声明。

    如果函数声明了异常,调用者需要进行处理,处理方式可throws可以try。

    异常有两种:一种叫做编译时被检测异常(该异常在编译时,如果没有处理(没有抛也没有try),那么编译失败,该异常被标识,代表着可以被处理);一种叫做运行时异常(编译时不检测)(在编译时,不需要处理,编译器不检查,该异常的发生,建议不处理,让程序停止,需要对代码进行修正)

    异常处理语句:

    try{

      需要被检测的代码

    }catch(){

      处理异常的代码

    }finally{

      一定会处理的代码

    }

    有三种结合格式:

    try{

    }catch(){

    }

    try{

    }finally{

    }

    try{

    }catch(){

    }finally{

    }

    注意:

    1. finally中定义的通常是关闭资源代码,因为资源必须要释放。
    2. finally有一种情况读不到:即系统退出(System.exit(0)虚拟机结束时,finally不会再执行)

    自定义异常:

    定义类继承Exception或者RuntimeException

    1. 为了让该自定义类具备可抛性
    2. 让该类具备操作异常的共性方法

    当要定义自定义异常的信息时,可以使用父类已经定义好的功能。异常信息传递给父类的构造函数

    class MyException extends Exception{

    MyException(String message){

      super(message);

    }

    }

    自定义异常:

    按照java的面向对象思想,将程序中出现的特有问题进行封装

    自定义异常好处:

    1. 将问题进行封装
    2. 将正常流程代码和问题处理代码相分离,方便阅读

    异常的处理原则:

    1. 处理方式有两种:try 或者throws
    2. 调用到抛出异常的功能时,抛出几个,就处理几个(不多抛不多处理)。一个try对应多个catch的情况。
    3. 多个catch,父类的catch放到最下面
    4. catch内需要定义针对性的处理方式,不要简单的定义printStackTrace输出语句,也不要不写。当捕获到的异常,本功能处理不了时,可以继续在catch中抛出即:

    try{

      throw new AException();

    }catch(AException e){

      throw e;

    }

    如果该异常处理不了,但并不属于该功能出现的异常,可以将异常妆花后,再抛出和该功能相关的异常。

    或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,让调用者知道,并处理。也可以将捕获异常处理后,转换为新的异常

    try{

      throw new AException();

    }catch(AException e){

      //捕获到AException但是AException处理不了,可以转换为新的异常处理类

     throw new BException();

    }

    比如,汇款的例子

    异常的注意事项:

    在子父类覆盖时:

    1. 子类抛出的异常必须是父类的异常的子类或者子集;
    2. 如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛

    参阅:ExceptionTest.java 老师用电脑上课

          ExceptionTest1.java图形的面积

    11.12异常—练习四

    如上图,首先执行main中的func()方法,调用到func(),执行try抛异常,执行finally中B,再由main()中捕捉到异常执行main中catch得到C,A在func()有异常后不再执行,再执行D,所以,输出为B  C  D。

    如上图,main方法中首先执行new Demo后,执行到默认的super()方法(默认有,没有写而已),从而执行到其父类Test类,输出Test,然后输出Demo,在执行main中new Test(),输出Test。

    在多态中(父类有指向子类对象时)成员函数的特点:

    在编译时期,参阅引用型变量(Fu类)所属的类中是否有调用的方法,如果有编译通过,如果没有编译失败;//此处A接口中没有定义func()方法,所以编译失败

    在运行时期,参阅对象(Zi类)所属的类中是否有调用的方法。

    如上图,首次执行到for循环时,f.show(‘A’)执行Demo类中Demo()方法,打印A输出false,而f.show(‘B’)也执行Demo类中的Demo()方法打印B输出false满足条件,(i<2)不再执行,因此循环直接结束。(在运行时期,参阅对象(Zi类)所属的类中是否有调用的方法。)。

    如上图,A接口中没有定义Test方法,编译失败。

    如上图,执行main中new Demo(“A”)后,执行到Demo类中构造方法,而其中会有个默认的super()方法,从而执行到父类Super中的狗仔函数Super(),从而打印B,执行i+=2,然后继续执行Demo类中Demo()构造函数中代码,打印C,将i赋值为5,然后继续执行mian(),从而打印d.i  为5

    如上图,定义匿名内部类的前提:内部类必须继承一个类,或者实现接口。

    interface Inter{

    void show(int a,int b);

    void func();

    }

    class Demo {

    public static void main(String[] args){

      Inter in = new Inter(){

        public void show(int a,int b){}

        public void func(){}

    }

    in.show();

    in.func();

    }

    }

    匿名内部类一定要在方法上加上public标识共有;

    要调用匿名内部类的多个方法,使用Inter in = new Inter(){}格式后,用实例名in调用即可

    如上图,编译失败,非静态内部类,不可以定义静态成员;

    内部类中如果定义了静态成员,该内部类必须被静态修饰

    如上图,读清楚题目,是存在于Demo的子类中,不是再同一个函数的重载

    A 可以,覆盖

    B 不可以 权限不够

    C 可以  和父类不是一个函数。没有覆盖相当于重载

    D 不可以,因为该函数不可以和给定函数出现在同一类中,或者子父类中

    E 不可以,静态只能覆盖静态

    this:代表本类对象,哪个对象调用this所在函数,this就代表哪个对象

    final:

    1. 修饰类,变量(成员变量、静态变量、局部变量),函数
    2. 修饰的类不可以被继承
    3. 修饰的方法不可以被覆盖
    4. 修饰的变量是一个常量,只能赋值一次
    5. 内部类只能访问局部的final形式变量

    11.

    如上图,输出结果:4  5  showZi  showZi

    成员变量看左边,变量不存在覆盖;

    方法看右边

     

    如上图,定义成员变量,然后计算和

    局部接收进来的,值改变后,其他方法也可以用

    如上图,输出BCD

    如上图,编译失败,应该父类中缺少空参数的构造函数;或者子类应该通过super语句指定要调用的父类中的构造函数

    如上图,编译失败:因为子父类中的get方法没有覆盖,子类调用的时候不能明确返回值是什么类型,所以这样的函数不能存在在子父类中。

    如上图,编译失败:因为打印字符串“A”的输出语句执行不到。

    如上图,16题和13题区:把抛出异常封装在方法中,代表有可能有问题,有可能没有问题,所以13题中的A是有可能执行到的,但是16题中A绝对不可能执行到。

    如上图,A ok 

    B 不可以,因为主函数是静态的,如果要访问inner需要被static修饰

    C 错误,格式错误

    D 错误 因为inner不是静态的

    编译失败,多个catch时,父类的catch要放在最下面。

     

     

    如上图,方法时静态的,所以调用多次后,前面一次方法不会销毁,且output也是共享的不会销毁,foo(0)执行后,在执行foo(1)时继续累加

    return语句后,finally中的语句继续执行,但是finally外的不会继续执行

    所以结果是 13423         

     

    已经做过

     

     

    输出4

     

    已经做过

    如上图,数组查找,数组可能无序,所以不要折半

     

    如上图,用到本类对象this

    前面的cir用this表示,cir2传入

    12包

    12.1包package

    1. 对类文件进行分类管理
    2. 给类提供多层命名空间
    3. 写在程序文件的第一行
    4. 类名的全称是 包名.类名
    5. 包也是一种封装形式

    命令中加参数用于创建包的目录

    javac –d . PackageDemo.java

    -d 指定包所存放的位置

    . 表示当前目录

    PackageDemo.java 类名

    执行时:

    java pack.PackageDemo

    不存在当前目录(而存放到指定目录):

    javac –d c:\ PackageDemo.java

    set classpath–c:\  指向包(pack)的父目录即可

    java pack.PackageDemo

    包的出现可以让java的类文件和class文件相分离,当别人要执行时,可以只给class运行文件,而不用给源文件

    12.2包与包之间的访问

     

    先编译DemoA,再编译PackageDemo

    编译时将编译文件存在存一个路径

    发现报错。

    错误原因:类名写错

    因为类名的全名是:包名.类名

    改正后:

    发现又报错:

    错误原因:软件包不存在

    packa包不再当前目录下,需要设置classpath,告诉JVM去哪里找指定的packa包

    包找到了,但是又发现其他错误

    有了包,范围变大,一个保重的类要被访问,必须要有足够大的权限,所以要被访问的类需要被public修饰

    因为DemoA类的修饰符没有权限

    类的修饰符有两个:protected、public

    改完后发现其他错误:

    错误原因:类共有后,被访问的成员也要共有才可以被访问

    改正后,运行正确

    总结:

    • 包与包之间进行访问,被访问的包中的类以及类中的成员,需要public修饰
    • 不同包中的子类还可以直接访问父类中被protected权限修饰的成员(java给包与包中的方法提供权限protected权限(默认),使其不继承也可以拿到某类中的方法)

    包与包之间使用的权限只有两种:public和protected(只能给子类用)

     

    public

    protected

    default

    private

    同一类中

    Ok

    Ok

    Ok

    Ok

    同一包中

    Ok

    Ok

    Ok

     

    子类

    Ok

    Ok

     

     

    不同保重

    Ok

     

     

     

    一个java文件里不能出现两个公有类或接口:(以下代码错误)

    可以将两个文件放在同一个包下

    12.3导入import

    为了简化类名的书写,使用一个关键字:import

    同一目录下有多个类时,使用*,导入到文件

    import导入的是包中的类,如果有包是不能导入的

    建议不要写通配符*,需要用到包中的那个类就导入哪个类,否则占用内存太多

    导入不同包的同名的包时,必须写清楚类的全名(包名+类名)

    如上例,packa和backb包中存在同名的DemoC类时,使用时,必须写DemoCracy的全名packa.DemoC c = new packa.DemoC();

    建议定义包名时不要重复,可以使用URL来完成定义,URL是唯一的

    12.4jar包

    java的压缩包

    1. 方便项目的携带
    2. 方便与使用,只要在classpath设置jar路径即可
    3. 数据库驱动,SSH框架等都是以jar包体现的

    java打jar包需要借助java JDK工具java.exe

    jar命令的用法:

    如:

    -c 创建新的归档文件

    -f 创建的归档文件名

    haha.jar jar包名字

    packa pack 需要打成包的文件夹(注:命令必须在当前文件夹下执行,如例两个文件夹在myclass文件下)

    jar包和打成其他包的区别:

    jar –tf haha.jar  查看归档目录

    存放了java特有的配置文件,且

    目录下存放的文件都删除了,双击jar包时仍然可以执行的。如下,

    使用jar –cvf a.jar packa pack  可以显示打印时的详细信息

    jar –tvf a.jar packa pack 可以显示时间等详细信息

    数据重定向

    将打包时的数据定向到1.txt文件夹内:

    将jar包中所有的类重定向放到rt.txt文件中

    展开全文
  • 【含答案】第二章 类与对象--2.1-面向对象方法的特性 (1)单选题 面向对象的程序设计方法采用了什么样的抽象方法构建程序的类与对象: A 过程抽象 B 数据抽象 C 过程抽象与数据抽象 D 没有采用任何的抽象方法 (2...

    【含答案】第二章 类与对象--2.1-面向对象方法的特性
    (1)单选题

    面向对象的程序设计方法采用了什么样的抽象方法构建程序的类与对象:

    A   过程抽象
    B   数据抽象
    C   过程抽象与数据抽象
    D   没有采用任何的抽象方法
    (2)单选题

    下面关于抽象概念的描述中,不正确的是

    A   计算机软件开发使用的抽象有过程抽象和数据抽象两种
    B   过程抽象强调功能完成的过程和步骤
    C   过程抽象按照功能将整个系统的不同部分抽象成不同的类
    D   数据抽象的每个抽象数据类型包含了数据和针对这些数据的操作
    (3)单选题

    下面关于面向对象概念的描述中,不正确的一项是

    A   在现实生活中,对象是指客观世界的实体
    B   程序中的对象就是现实生活中的对象
    C   在程序中,对象是通过一种抽象数据类型来描述的,这种抽象数据类型称为类
    D   在程序中,对象是一组变量和相关方法的集合
    (4)单选题

    下列不属于面向对象程序设计的基本特征的是:

    A   抽象
    B   封装
    C   继承
    D   静态
    (5)单选题

    Java的封装性是通过什么实现的:

    A   访问控制权限
    B   设计内部类
    C   静态域与静态方法
    D   包
    (6)单选题

    Java语言间的继承关系是:

    A   单继承
    B   多继承
    C   单继承和多继承
    D   不能继承
    (7)单选题

    以下说法中对Java中 定义的父类与子类的关系描述正确是的:

    A   一个子类可以有多个父类,一个父类也可以有多个子类
    B   一个子类可以有多个父类,但一个父类只可以有一个子类
    C   一个子类可以有一个父类,但一个父类可以有多个子类
    D   上述说法都不对

    获取标准答案

    展开全文
  • 面向对象的开发方法

    千次阅读 2015-06-17 11:54:33
    面向对象的开发方法(Object Oriented,OO)  从事软件开发的工程师们常常有这样的体会:在软件开发过程中,使用者会不断地提出各种更改要求,即使在软件投入使用后,也常常需要对其做出修改,在用结构化开发的程序...

    转自:http://www.cnblogs.com/X8023Z/archive/2008/12/04/oo33.html

    面向对象的开发方法(Object Oriented,OO)

        从事软件开发的工程师们常常有这样的体会:在软件开发过程中,使用者会不断地提出各种更改要求,即使在软件投入使用后,也常常需要对其做出修改,在用结构化开发的程序中,这种修改往往是很困难的,而且还会因为计划或考虑不周,不但旧错误没有得到彻底改正,又引入了新的错误;另一方面,在过去的程序开发中,代码的重用率很低,使得程序员的效率并不高,为提高软件系统的稳定性、可修改性和可重用性,人们在实践中逐渐创造出软件工程的一种新途径――面向对象方法学。

    一、面向对象的方法(OO方法)简介

     面向对象方法学的出发点和基本原则是尽可能模拟人类习惯的思维方式,使开发软件的方法与过程尽可能接近人类认识世界、解决问题的方法与过程。由于客观世界的问题都是由客观世界中的实体及实体相互间的关系构成的,因此我们把客观世界中的实体抽象为对象(Object)。持面向对象观点的程序员认为计算机程序的结构应该与所要解决的问题一致,而不是与某种分析或开发方法保持一致,他们的经验表明,对任何软件系统而言,其中最稳定的成分往往是其相应问题论域(problem domain)中的成分。(例如在过去几百年中复式计帐的原则未做任何实质性的改变,而其使用的工具早已从鹅毛笔变成了计算机。)

        所以,“面向对象”是一种认识客观世界的世界观,是从结构组织角度模拟客观世界的一种方法。一般人们在认识和了解客观现实世界时,通常运用的一些构造法则:

    • 区分对象及其属性,例如区分台式计算机和笔记本计算机;

    • 区分整体对象及其组成部分,例如区分台式计算机组成(主机、显示器等);

    • 不同对象类的形成以及区分,例如所有类型的计算机(大、中、小型计算机、服务器、工作站和普通微型计算机等)。

     通俗地讲,对象指的是一个独立的、异步的、并发的实体,它能“知道一些事情” (即存储数据),“做一些工作”(即封装服务),并“与其它对象协同工作”(通过交换消息),从而完成系统的所有功能。

     因为所要解决的问题具有特殊性,所以对象是不固定的。一个雇员可以作为一个对象,一家公司也可以作为一个对象,到底应该把什么抽象为对象,由所要解决的问题决定。

     从以上的简单介绍中我们可以看出,面向对象所带来的好处是程序的稳定性与可修改性(由于把客观世界分解成一个一个的对象,并且把数据和操作都封装在对象的内部)、可复用性(通过面向对象技术,我们不仅可以复用代码,而且可以复用需求分析、设计、用户界面等等)。

     面向对象方法具有下述四个要点:

    1.认为客观世界是由各种对象组成的,任何事物都是对象,复杂的对象可以由比较简单的对象以某种方式组合而成。按照这种观点,可以认为整个世界就是一个最复杂的对象。因此,面向对象的软件系统是由对象组成的,软件中的任何元素都是对象,复杂的软件对象由比较简单的对象组合而成。

    2.把所有对象都划分成各种对象类(简称为类(Class)),每个对象类都定义了一组数据和一组方法,数据用于表示对象的静态属性,是对象的状态信息。因此,每当建立该对象类的一个新实例时,就按照类中对数据的定义为这个新对象生成一组专用的数据,以便描述该对象独特的属性值。

     例如,荧光屏上不同位置显示的半径不同的几个圆,虽然都是Circle类的对象,但是,各自都有自己专用的数据,以便记录各自的圆心位置、半径等等。

        类中定义的方法,是允许施加于该类对象上的操作,是该类所有对象共享的,并不需要为每个对象都复制操作的代码。

    3.按照子类(或称为派生类)与父类(或称为基类)的关系,把若干个对象类组成一个层次结构的系统(也称为类等级)。

    4.对象彼此之间仅能通过传递消息互相联系。

     

    二、OO方法的基本思想

       对象是事物运行方式、处理方法和属性值的一种抽象表述。它是严格信息包和有关信息包的操作描述;它是事物的本质,不会随周围环境改变而变化的相对固定的最小的集合。它可用一组属性和可以执行的一组操作来定义。

        例:在计算机屏幕上画多边形,每个多边形是一个用有序顶点的集所定义的对象。

        这些顶点的次序决定了它们的连接方式,顶点集定义了一个多边形对象的状态,包括它的形状和它在屏幕上的位置,在多边形上的操作包括:draw(屏幕显示) move(移动) contains(检查某点是否在多边形内)

        类是一组具有相同数据结构和相同操作的对象的集合。

        类的定义包括一组数据属性和在数据上的一组合法的操作。在一个类中,每个对象都是类的实例(instance同类的对象具有相同的方法集。

     

        类还具有父类、子类之分。父类高层次的类,表达共性,子类低层次表达个性。子类通过继承机制获得父类的属性和操作。例如:电视机、电话、计算机等都是电子产品,它们具有电子产品的公共特性,当定义电视机类Video,电话类Telephone和计算机类Computer时候,为避免它们公共特性的重复编码,可将这些电子产品的公共特性部分定义为电子产品类,将Video,Telephone和Computer定义为它的子类,子类继承了父类的所有属性和操作,而且子类自己还可扩充定义自己的属性和操作:如电子产品类具有型号、价格、颜色等属性,computer则继承了这些属性,并扩充自己的属性:显示类型、内存大小等属性。

    1.发现对象的途经

    (1)古典法
    候选的对象和类通常来自下列来源:
    有形事物:汽车、气象数据、压力传感器。
    角色:父亲、教师、医生、女兵。
    事件:降落、中断、要求。
    交互作用:借款、会议、交叉。
    候选的对象还可能来自:
    结构:“ 是一个”及“ …的部分”关系。
    其它系统:与待研制系统有交往的其它系统。
    承担的角色:用户与待研制系统交往时所承担的不同角色,如站长、站调、统计员等。
    地点:待研制系统中重要的具体地点、办公处以及场所,如信号楼、技术科、调度室。
    组织单位:用户所属组织,如生产部、经营部、总务处等。
    (2)领域分析法
        古典法是集中于问题的有形事物,而领域分析法则集中于问题领域中重要的对象、操作以及关系识别。其任务是在某一问题领域中识别出所有一切应用问题共有的客体和类,例如,销售、会计、债券交易、编译程序等都是问题领域。
        
    领域分析法举例
        例如,需要研制一个邮政销售(函售)系统,所考虑的函售应用问题如它们的关健对象一时想不出来,可对整个销售领域进行领域分析,即从现存的零售、批发系统中发现那些一时想不出来的对象,或得到启发而定出所需对象。
    (3)结构化分析法

      它是利用结构化分析的成果,如DFD(数据流程图)、实体关系图、数据字典等,找出和识别对象。
        数据流程图中的数据存储、外部实体,有些非系统内部的数据流(它可来自外部的刺激或系统对外界的响应)等均可以作为候选对象。如存户来银行存款,即是外部对银行存款系统的的一个刺激,其数据内容是存户款;给存户的月终结算,是系统对外部的响应。 

    2.对象具有如下特征

       模块性对象是一个独立存在的实体。从外部可以了解它的功能,其内部细节是“ 隐蔽”的不受外界干扰。对象之间的相互依赖性很小。所以,模块性体现了抽象和信息的隐蔽。它使得一个复杂的软件系统可以通过定义一组相对独立的模块来实现,这些独立模块彼此之间只需交换那些为了完成系统功能所必须交换的信息。当模块内部实现发生变化而导致代码修改时,只要对外接口操作的功能不变,就不会给软件系统带来影响。

        继承和类比性对象之间属性关系的共同性,即子模块继承了父模块的属性;通过类比方法抽象出典型对象的过程为类比。

        继承:是利用已有的定义作为基础来建立新的定义,而不必重复定义它们。
    例如,汽车具有“ 型号”、“ 年代”和“ 引擎”等属性,其子类吉普车、轿车及卡车都继承了这些属性。

        动态连接性各个对象之间统一、方便、动态的消息传递机制。它是面向对象语言的共同特性,其含义是将一条发送给一个对象的消息与包含该消息的方法的对象联接起来,它使得增加新的数据类型不需要改变现有的代码

     

    3.以对象为主体的OO方法

      (1)客观事物都是由对象(object)组成的,对象是在原事物基础上抽象的结果。任何复杂的事物都可以通过对象的组合构成。

       (2)对象由属性(attribute)和方法组成。属性反映了对象的信息特征,如:特点、值、状态等等;方法(method)则是用来定义改变属性状态的各种操作。

        例如:电视机对象的属性有颜色、音量、亮度、频道等,其上的操作有调节颜色、调节音量、调节亮度、调节频道等。

        如:图书馆系统中其业务过程和业务实体中,最基本的对象类只有读者和复本。最基本的业务操作只有借阅和查询。

     

      (3)对象之间的联系主要是通过传递消息(message来实现的,而传递的方式是通过消息模式(message pattern)和方法所定义的操作过程来完成的。

        例如当用户请求document的对象打印它自己时,该文档可发送一消息给对象printer以在打印队列中请求一位置,而printer则可发送一消息返回至该文档以要求对信息加以格式化。消息还可包含解释一请求的信息。如请求一对象打印其自身的消息可包含打印机名。

      (4)对象可按照其属性进行归类(class,类有一定的结构,类上有超类(父类),类下有子类。这种对象或类之间的层次结构是靠继承关系维系着的。一般父类具有通用性,子类具有特殊性。例如:

    图4-4-1 类、子类、超类关系


        segment是一个对象,paragraph和table共享某些性质,则可用更抽象的类text表示;paragraph也是一个类,它虽是segment的父类却是text的子类,text是类document的子类,text是table的超类(父类)。

        又如汽车是轿车、吉普车及卡车的父类,轿车、吉普车及卡车是汽车的子类。父类和子类是相对的。父类之上可有另一父类,而成为其子类。

       (5)对象是一个被严格模块化的实体,称为封装(encapsulation)。这种封装了的对象满足软件工程的一切要求,而且可以直接被面向对象的程序设计语言所接受。

        例如,电视机箱将电视内部的显象管、印刷板、元件和线路都封装起来了。人们只能通过电视机面板上按钮改变其属性(颜色、音量、亮度、频道、制式等)。

        有关对象的概念还有下列相关的一些内容:

    •   实例(Instance)

        实例就是由某个特定的类所描述的一个具体的对象。类是对具有相同属性和行为的一组相似的对象的抽象,类在现实世界中并不能真正存在。在地球上并没有抽象的“中国人”,只有一个个具体的中国人,例如,张三、李四、王五,同样,谁也没见过抽象的“圆”。

        实际上类是建立对象时使用的“样板”,按照这个样板所建立的一个个具体的对象,就是类的实际例子,通常称为实例。

    •   消息(Message)

    对象之间进行通信的一种构造叫做消息,当一个消息发送给某个对象时,包含要求接收对象去执行某些活动的信息。接收到消息的对象经过解释,然后予以响应。这种通信机制叫做消息传递。发送消息的对象不需要知道接收消息的对象如何对请求予以响应。通常,一个消息由下述三部分组成:

    (a)接收消息的对象;

    (b)消息选择符(也称为消息名);

    (c)零个或多个变元。

    •   方法(Method)

        方法,就是对象所能执行的操作,也就是类中所定义的服务。方法描述了对象执行操作的算法,响应消息的方法。在C++语言中把方法称为成员函数。

        例如,在录音机的例子中,为了能让使用者按下“放音键”就开始播放磁带,必须在录音机类中给出“按下放音键”的定义,也就是给出这个动作的实现方法。

    •   属性(Attribute)

        属性,就是类中所定义的数据,它是对客观世界实体所具有的性质的抽象。类的每个实例都有自己特有的属性值。

        例如,在录音机类中定义的代表录音机的型号、外观、电压等数据就是属性。

    •   继承(Inheritance)

        广义地说,继承是指能够直接获得已有的性质和特性,而不必重复定义它们。在面向对象的软件技术中,继承是子类自动地共享基类(或父类)中定义的数据和方法的机制。一个类直接继承其父类的全部描述(数据和操作)。

        继承具有传递性,继承性使得相似的对象可以共享程序代码和数据结构,从而大大减少了程序中的冗余信息。使得对软件的修改变得比过去容易得多了。

        继承性使得用户在开发新的应用系统时不必完全从零开始,可以继承原有的相似系统的功能或者从类库中选取需要的类,再派生出新的类以实现所需要的功能,所以,继承的机制主要是支持程序的重用和保持接口的一致性。

    •   多态性(Polymorphism)

        在面向对象的软件技术中,多态性是指子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。也就是说,在类等级的不同层次中可以共享(公用)一个行为(方法)的名字,然而不同层次中的每个类却各自按自己的需要来实现这个行为。当对象接收到发送给它的消息时,根据该对象所属于的类动态选用在该类中定义的实现算法。

    •   重载(Overloading)

        有两种重载:函数重载是指在同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字;运算符重载是指同一个运算符可以施加于不同类型的操作数上面。当然,当参数特征不同或被操作数的类型不同时,实现函数的算法或运算符的语义是不相同的。

        重载进一步提高了面向对象系统的灵活性和可读性。

     

    OO方法的开发过程

       OO方法开发过程分为4个阶段:

      1.系统调查和需求分析:对系统面临的问题和用户的开发需求进行调查研究。

      2.分析问题的性质和求解问题:在复杂的问题域中抽象识别出对象及其行为、结构、属性和方法。这一个阶段一般称为面向对象分析,即OOA

      3.整理问题:对分析的结果进一步抽象、归类整理,最终以范式的形式确定下来,即OOD

      4.程序实现:使用面向对象的程序设计语言将其范式直接映射为应用程序软件,即OOP(它是一个直接映射过程)。

    OOA方法(面向对象分析)

    本节着重讨论面向对象分析(Object-Oriented Analysis, OOA)。

    面向对象分析与其它分析方法一样,是提取系统需求的过程。

    面向对象分析的关键,是识别出问题域内的对象,并分析他们相互间的关系,最终建立起问题域的正确模型。

    通常,面向对象分析过程从分析陈述用户需求的文件开始。需求陈述的内容包括:问题范围,功能需求,性能需求,应用环境及假设条件等。总之,需求陈述应该阐明“做什么”而不是“怎样做”。它应该描述用户的需求而不是提出解决问题的方法。在利用面向对象开发方法时,书写需求陈述要尽力做到语法正确,而且应该慎重选用名词、动词、形容词和同义词。

    接下来,系统分析员应该深入理解用户需求,抽象出目标系统的本质属性,并用模型准确地表示出来。

    面向对象分析大体上按照下列顺序进行:建立功能模型、建立对象模型、建立动态模型、定义服务。

    1.建立功能模型

        功能模型从功能角度描述对象属性值的变化和相关的函数操作,表明了系统中数据之间的依赖关系以及有关的数据处理功能,它由一组数据流图组成。其中的处理功能可以用IPO图、伪码等多种方式进一步描述。

        建立功能模型首先要画出顶层数据流图,然后对顶层图进行分解,详细描述系统加工、数据变换等,最后描述图中各个处理的功能。

    2.建立对象模型

        复杂问题(大型系统)的对象模型由下述五个层次组成:主题层(也称为范畴层)、类-&-对象层、结构层、属性层和服务层,如图4-4-2所示。

    图4-4-2 对象模型的层次

        这五个层次很像叠在一起的五张透明塑料片,它们一层比一层显现出对象模型的更多细节。在概念上,这五个层次是整个模型的五张水平切片。

        建立对象模型典型的工作步骤是:首先确立对象类和关联,对于大型复杂的问题还要进一步划分出若干主题;然后给类和关联增添属性,以进一步描述它们;接下来利用适当的继承关系进一步合并和组织类。

    (1)确定类-&-对象

        类-&-对象是在问题域中客观存在的,系统分析员的主要任务就是通过分析找出这些类-&-对象。首先,找出所有候选的类-&-对象;然后,从候选的类-&-对象中筛选掉不正确的或不必要的项。

    步骤1:找出候选的类-&-对象

        对象是对问题域中有意义的事物的抽象,它们既可能是物理实体,也可能是抽象概念,在分析所面临的问题时,可以参照几类常见事物,找出在当前问题域中的候选类-&-对象。

        另一种更简单的分析方法,是所谓的非正式分析。这种分析方法以用自然语言书写的需求陈述为依据,把陈述中的名高速作为类-&-对象的候选者,用形容词作为确定属性的线索,把动高速作为服务(操作)候选者。当然,用这种简单方法确定的候选者是非常不准确的,其中往往包含大量不正确的或不必要的事物,还必须经过更进一步的严格筛选。通常,非正式分析是更详细、更精确的正式的面向对象分析的一个很好的开端。

    步骤2:筛选出正确的类-&-对象

        非正式分析仅仅帮助我们找到一些候选的类-&-对象,接下来应该严格考察候选对象,从中去掉不正确的或不必要的,仅保留确实应该记录其信息或需要其提供服务的那些对象。筛选时主要依据下列标准,删除不正确或不必要的类-&-对象:

    <1>冗余(如果两个类表达了同样的信息)

    <2>无关(仅需要把与本问题密切相关的类-&-对象放进目标系统中)

    <3>笼统(需求陈述中笼统的、泛指的名词)

    <4>属性(在需求陈述中有些名词实际上描述的是其它对象的属性)

    <5>操作(正确地决定把某些词作为类还是作为类中定义的操作)

    <6>实现(去掉仅和实现有关的候选的类-&-对象)

    (2)确定关联

        两个或多个对象之间的相互依赖、相互作用的关系就是关联。分析确定关联,能促使分析员考虑问题域的边缘情况,有助于发现那些尚未被发现的类-&-对象。

    步骤1.初步确定关联

        在需求陈述中使用的描述性动词或动词词组,通常表示关联关系。因此,在初步确定关联时,大多数关联可以通过直接提取需求陈述中的动词词组而得出。通过分析需求陈述,还能发现一些在陈述中隐含的关联。最后,分析员还应该与用户及领域专家讨论问题域实体间的相互依赖、相互作用关系,根据领域知识再进一步补充一些关联。

    步骤2.自顶向下

        把现有类细化成更具体的子类,这模拟了人类的演绎思维过程。从应用域中常常能明显看出应该做的自顶向下的具体化工作。例如,带有形容词修饰的名词词组往往暗示了一些具体类。但是,在分析阶段应该避免过度细化。

    (3)定义结构

        结构指的是多种对象的组织方式,用来反映问题空间中的复杂事物和复杂关系。这里的结构包括两种:分类结构与组装结构。分类结构针对的是事物的类别之间的组织关系,组织结构则对应着事物的整体与部件之间的组合关系。

        使用分类结构,可以按事物的类别对问题空间进行层次化的划分,体现现实世界中事物的一般性与特殊性。例如在交通工具、汽车、飞机、轮船这几件事物中,具有一般性的是交通工具,其它则是相对特殊化的。因此可以将汽车、飞机、轮船这几种事物的共有特征概括在交通工具之中,也就是把对应于这些共有特征的属性和服务放在“交通工具”这种对象之中,而其它需要表示的属性和服务则按其特殊性放在“汽车”、“飞机”、“轮船”这几种对象之中,在结构上,则按这种一般与特殊的关系,将这几种对象划分在两个层次中,如图4-4-3所示:

    4-4-3  分类结构示例 

        组织结构表示事物的整体与部件之间的关系。例如把汽车看成一个整体,那么发动机、变速箱、刹车装置等都是汽车的部件,相对于汽车这个整体就分别是一个局部。

    (4)识别主题

        对一个实际的目标系统,特别是大的系统而言,尽管通过对象和结构的认定对问题空间中的事物进行了抽象和概括,但对象和结构的数目仍然是可观的,因此如果不对数目众多的对象和结构进行进一步的抽象,势必造成对分析结果理解上的混乱,也难以搞清对象、结构之间的关联关系,因此引入主题的概念。

    主题是一种关于模型的抽象机制,它给出了一个分析模型的概貌。

    主题直观地来看就是一个名词或名词短语,与对象的名字类似,只是抽象的程度不同。识别主题的一般方法是:为每一个结构追加一个主题;为每一种对象追加一个主题;如果当前的主题的数目超过了7个,就对已有的主题进行归并,归并的原则是,当两个主题对应的属性和服务有着较密切的关联时,就将它们归并成一个主题。

    (5)认定属性

    属性是数据元素,用来描述对象或分类结构的实例。

    认定一个属性有三个基本原则:首先,要确认它对响应对象或分类结构的每一个实例都是适用的;其次,对满足第一个条件的属性还要考察其在现实世界中与这种事物的关系是不是足够密切;第三,认定的属性应该是一种相对的原子概念,即不依赖于其它并列属性就可以被理解。

     

    3.建立动态模型

    当问题涉及交互作用和时序时(例如用户界面及过程控制等),建立动态模型则是很重要的。

    建立动态模型的第一步,是编写典型交互行为的脚本。脚本是指系统在某一执行期间内出现的一系列事件。编写脚本的目的,是保证不遗漏重要的交互步骤,它有助于确保整个交互过程的正确性和清晰性。

    第二步从脚本中提取出事件,确定触发每个事件的动作对象以及接受事件的目标对象。

    第三步,排列事件发生的次序,确定每个对象可能有的状态以及状态间的转换关系。

    最后,比较各个对象的状态,检查它们之间的一致性,确保事件之间的匹配。 

    4.定义服务

        通常在完整地定义每个类中的服务之前,需要先建立起动态模型和功能模型,通过对这两种模型的研究,能够更正确更合理地确定每个类应该提供那些服务。

        正如前面已经指出的那样,“对象”是由描述其属性的数据,及可以对这些数据施加的操作(即服务)封装在一起构成的独立单元。因此,为建立完整的动态模型,既要确定类的属性,又要定义类的服务。在确定类中应有的服务时,既要考虑类实体的常规行为,又要考虑在本系统中特殊需要的服务。

     首先考虑常规行为:在分析阶段可以认为类中定义的每个属性都是可以访问的,即假设在每个类中都定义了读、写该类每个属性的操作。

     其次,从动态模型和功能模型中总结出特殊服务。

     最后应该尽量利用继承机制以减少所需定义的服务数目。

     

    五、OOD方法(面向对象的设计)

        如前所述,分析是提取和整理用户需求,并建立问题域精确模型的过程。设计则是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。从面向对象分析到面向对象设计(通常缩写为OOD),是一个逐渐扩充模型的过程。或者说,面向对象设计就是用面向对象观点建立求解域模型的过程。

        尽管分析和设计的定义有明显区别,但是在实际的软件开发过程中二者的界限是模糊的。许多分析结果可以直接映射成设计结果,而在设计过程中又往往会加深和补充对系统需求的理解,从而进一步完善分析结果。因此,分析和设计活动是一个多次反复迭代的过程。面向对象方法学在概念和表示方法上的一致性,保证了在各项开发活动之间的平滑(无缝)过渡,领域专家和开发人员能够比较容易地跟踪整个系统开发过程,这是面向对象方法与传统方法比较起来所具有的一大优势。

     

    1.面向对象设计的准则

        在以前的软件设计中人们总结出几条基本原理,这些原理在进行面向对象设计时仍然成立,但是增加了一些与面向对象方法密切相关的新特点,从而具体化为下列的面向对象设计准则:

    (1)  模块化

        面向对象软件开发模式,很自然地支持了把系统分解成模块的设计原理:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。

    (2)  抽象

        抽象表示对规格说明的抽象(abstraction by specification)和参数化抽象(abstraction by parametrization)。

    (3)  信息隐藏

        在面向对象方法中,信息隐藏通过对象的封装性实现:类结构分离了接口与实现,从而支持了信息隐藏。对于类的用户来说,属性的表示方法和操作的实现算法都应该是隐藏的。

    (4)  弱耦合

        在面向对象方法中,对象是最基本的模块,因此,耦合主要指不同对象之间朴素关联的紧密程度。弱耦合是优秀设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其它部分的影响降到最低程度。

        当然,对象不可能是完全孤立的,当两个对象必须朴素联系、朴素依赖时,应该通过类的协议(即公共接口)实现耦合,而不应该依赖于类的具体实现细节。

    (5)  强内聚

        设计中使用的一个构件内的各个元素,对完成一个定义明确的目的所做出的贡献程度。在设计时应该力求做到高内聚。在面向对象设计中存在下述三种内聚:

        <1>服务内聚

        一个服务应该完成一个且仅完成一个功能。

        <2>类内聚

        一个类应该只有一个用途。

        <3>一般-特殊内聚

        设计出的一般-特殊结构,应该符合多数人的概念。

    (6)  可重用

        软件重用是提高软件开发生产率和目标系统质量的重要途径。重用也叫再用或复用,是指同一事物不作修改或稍加改动就多次重复使用。重用是从设计阶段开始的。重用有两方面的含义:一是尽量使用已有的类(包括开发环境提供的类库,及以往开发类似系统时创建的类),二是如果确实需要创建新类,则在设计这些新类的协议时,应该考虑将来的可重复使用性。

        软件成分的重用可以进一步划分成以下三个级别:

    <1>代码重用

    <2>设计结果重用

     设计结果重用指的是,重用某个软件系统的设计模型(即求解域模型)。这个级别的重用有助于把一个应用系统移植到完全不同的软/硬平台上。

    <3>分析结果重用

     这是一种更高级别的重用,即重用某个系统的分析模型。这种重用特别适用于用户需求未改变,但系统体系结构发生根本变化的场合。

     通过分析软件重用的效果发现,重用率越高,生产率并不一定就越高。仅当开发人员使用已有软构件构造系统时,其工作效率比重新从底层编写程序的效率高时,重用率的提高才会导致生产率提高。可见,通过软件重用来提高软件生产率,并不是一件轻而易举的事情。软构件的实用程序和程度,以及软件开发人员的素质、开发环境等因素,都直接影响软件重用的效果。事实上,自20世纪60年代以来,人们就开始研究软件重用技术,主要目的是大幅度提高软件生产率,降低软件成本。但是,多年来始终没能有效地实现软件重用,直到面向对象技术崛起之后,才为软件重用带来了新的希望。

     

    2.面向对象设计的内容

        采用面向对象方法设计软件系统时,面向对象设计模型(即求解域的对象模型)与面向对象分析模型(即求问题域的对象模型)一样,也由主题、类-&-对象、结构、属性、服务等五个层次组成。这五个层次表示的细节一层比一层多,我们可以把这五个层次想象为整个模型的水平切片。此外,大多数系统的面向对象设计模型,在逻辑上都由四大部分组成。这四大部分对应于组成目标系统的四个子系统,它们分别是问题域子系统、人-机交互子系统、任务管理子系统和数据管理子系统。

    (1)设计问题域子系统

     通过面向对象分析所得出的问题域精确模型,为设计问题域子系统奠定了良好的基础,建立了完整的框架。只要可能,就应该保持面向对象分析所建立的问题域结构。通常,面向对象设计仅需从实现角度对问题域模型作一些补充或修改,主要是增添、合并或分解类-&-对象、属性及服务,调整继承关系等等。当问题域子系统过分复杂庞大时,应该把它进一步分解成若干个更小的子系统。

     下面介绍在面向对象设计过程中,可能对面向对象分析所得出的问题域模型的补充或修改:

    <1>调整需求

        有两种情况出现需要调整需求:用户需求或外部环境发生了变化;分析员对问题的理解存在问题。无论哪种情况出现,通常都只需要简单地修改分析的结果,然后把这些修改的结果反映到问题域子系统中。

    <2>重用已有的类

        代码重用从设计阶段开始,在研究面向对象分析结果时就应该寻找使用已有类的方法。若因为没有合适的类可以重用而确实需要创建新的类,则在设计这些新类的协议时,考虑到将来的可重用性。

    <3>把问题域类组合在一起

        在面向对象设计过程中,设计者往往通过引入一个根类而把问题域组合在一起,但这是在没有更先进的组合机制时才采用的一种组合方法。

    <4>增添一般化类以建立协议

    在设计过程中常常发现,一些具体类需要有一个公共的协议,也就是说,它们都需要定义一组类似的服务(很可能还需要相应的属性)。在这种情况下可以引入一个附加类(例如,根类)。

    <5>调整继承层次

        如果面向对象分析模型中包含了多重继承关系,然而所使用的程序设计语言却并不提供多重继承机制,则必须修改面向对象分析的结果。即使使用支持多重继承的语言,有时也会出于实现考虑而对面向对象分析结果作一些调整。

    (2)设计人-机交互子系统

        在面向对象分析过程中,已经对用户界面需求作了初步分析,在面向对象设计过程中,则应该对系统的人-机子系统进行详细设计,以确定人-机交互的细节,其中包括指定窗口和报表的形式、设计命令层次等项内容。人-机交互部分的设计结果,将对用户情绪和工作效率产生重要影响。

        <1> 设计人-机交互界面的准则

    一致性

    减少步骤

    及时提供反馈信息

    提供撤消命令

    无须记忆

    易学

    富有吸引力

        <2>设计人-机交互子系统的策略

    • 分类用户

        为设计好人-机交互子系统,设计者应该认真研究使用它的用户。设计者首先应该把将来可能与系统交互的分类。通常从下列几个不同角度进行分类:

    按技能水平分类(新手/初级/中级/高级)。

    按职务分类(总经理/经理/职员)。

    按所属集团分类(职员/顾客)。

    • 描述用户

        应该仔细了解未来使用系统的每类用户的情况,把获得的下列各项信息记录下来:

    用户类型。

    使用系统欲达到的目的。

    特征(年龄、性别、受教育程度、限制因素等)。

    关键的成功因素(需求、爱好、习惯等)。

    技能水平。

    完成本职工作的脚本。

    •   设计命令层次

    设计命令层次的工作通常包含以下几项内容:

    研究现有的人-机交互含义和准则

    现在,Windows已经成了微机上图形用户界面事实上的工业标准。

    确切初始的命令层

    所谓命令层次,实质上是用过程抽象机制组织起来的、可供选用的服务的表示形式。

    精化命令层次

    精化命令层次应考虑以下因素:次序、整体---部分关系、操作步骤。

    •   设计人-机交互类

    人-机交互类与所使用的操作系统及编程语言密切相关。

     

    (3)设计任务管理子系统

    虽然从概念上说,不同对象可以并发地工作。但是,在实际系统中,许多对象之间往往存在相互依赖关系。此外,在实际使用的硬件中,可能仅由一个处理器支持多个对象。因此,设计工作的一项重点就是,确定哪些是必须同时操作的对象,哪些是相互排斥的对象。然后进一步设计任务管理子系统。

    <1> 分析并发性

    彼此间不存在交互,或者它们同时接受事件,则这两个对象在本质上是并发的。通过检查各个对象的状态图及它们之间交换的事件,能够把若干个非并发的对象归并到一条控制线中。所谓控制线,是一条遍及状态图集合的路径,在这条路径上每次只有一个对象是活动的。在计算机系统中用任务(task)实现控制线,一般认为任务是进程(process)的别名。通常把多个任务的并发执行称为多任务。

    <2>  设计任务管理子系统

    常见的任务有事件驱动型任务、时钟驱动型任务、优先任务、关键任务和协调任务等。设计任务管理子系统,包括确定各类任务并把任务分配给适当的硬件或软件去执行。

    • 确定事件驱动型任务

    某些任务是由事件驱动的,这类任务可能主要完成通信工作。例如,设备、屏幕窗口、其它任务、子系统、另一个处理器或其它系统通信。事件通常是表明某些数据到达的信号。

    • 确定时钟驱动任务

    某些任务每隔一定时间间隔就被触发以执行某些处理,例如,某些设备需要周期性地获得数据;某些人-机接口、子系统、任务、处理器或其它系统也可能需要周期性地通信。在这些场合往往需要使用时钟驱动型任务。

    •   确定优先任务

    优先任务可以满足高优先级或低优先级的处理需求。

    高优先级:某些服务具有很高的优先级,为了在严格限定的时间内完成这种服务,可能需要把这类服务分离成独立的任务。

    低优先级:与高优先级相反,有些服务是低优先级的,属于低优先级处理(通常指那些背景处理)。设计时可能用额外的任务把这样的处理分离出来。

    •   确定关键任务

    关键任务是关系到系统成功或失败的那些关键处理,这类处理通常都有严格的可靠性要求。

    •   确定协调任务

    当系统中存在三个以上任务时,就应该增加一个任务,用它作为协调任务。

    •   确定资源需求

    使用多处理器或固件,主要是为了满足高性能的需求。设计者必须通过计算系统载荷来估算所需要的CPU(或其它固件)的处理能力。

    (4)设计数据管理子系统

    数据管理子系统是系统存储或检索对象的基本设施,它建立在某种数据存储管理系统之上,并且隔离了数据存储管理模式。

    <1>  选择数据存储管理模式

    文件管理系统、关系数据库管理系统、面向对象数据管理系统三种数据存储管理模式有不同的特点,适用范围也不同,其中文件系统用来长期保存数据,具有成本低和简单等特点,但文件操作级别低,为提供适当的抽象级别还必须编写额外的代码;关系数据库管理系统提供了各种最基本的数据管理功能,采用标准化的语言,但其缺点是运行开销大,数据结构比较简单;面向对象数据管理系统增加了抽象数据类型和继承机制,提供了创建及管理类和对象的通用服务。

    <2>  设计数据管理子系统

    设计数据管理子系统,既需要设计数据格式又需要设计相应的服务。设计数据格式包括用范式规范每个类的属性表以及由此定义所需的文件或数据库;设计相应的服务是指设计被存储的对象如何存储自己。

     

    、OOP方法( 面向对象实现)

    面向对象实现主要包括两项工作:把面向对象设计结果翻译成用某种程序语言书写的面向对象程序;测试并调试面向对象的程序。

    面向对象程序的质量基本上由面向对象设计的质量决定,但是,所采用的程序语言的特点和程序设计风格也将对程序的生成、可重用性及可维护性产生深远影响。

    1.程序设计

    (1)面向对象的语言与非面向对象的语言

    面向对象语言的形成借鉴了历史上许多程序语言的特点,从中吸取了丰富的营养。当今的面向对象语言,从50年代诞生的LISP语言中引进了动态联编的概念和交到式开发环境的思想,从60年代推出的SIMULA语言中引进了类的概念和继承机制,此外,还受到70年代末期开发的Modula-2语言和Ada语言中数据抽象机制的影响。

    100年代以来,面向对象语言像雨后春笋一样大量涌现,形成了两大类面向对象语言。一类是纯面向对象语言,如Smalltalk和Eiffel等语言。另一类是混合型面向对象语言,也就是在过程语言的基础上增加面向对象机制,如C++等语言。

    一般说来,纯面向对象语言着重支持面向对象方法研究和快速原型的实现,而混合型面向对象语言的目标则是提高运行速度和使传统程序员容易接受面向对象思想。成熟的面向语言通常都提供丰富的类库和强有力的开发环境。

    下面介绍在选择面向对象语言时应该着重考察的一些技术特点。

    <1>支持类与对象概念的机制

    所有面向对象语言都允许用户动态创建对象,并且可以用指针引用动态创建的对象。允许动态创建对象,就意味着系统必须处理内存管理问题,如果不及时释放不再需要的对象所占用的内存,动态存储分配就有可能耗尽内存。

    <2>实现整体--部分结构的机制

    一般说来,有两种实现方法,分别使用指针和独立的关联对象实现整体一部分结构。大多数现有的面向对象语言并不显示支持独立的关联对象,在这种情况下,使用指针是最容易的实现方法,通过增加内部指针可以方便地实现关联。

    <3>实现一般--特殊结构的机制

    既包括实现继承的机制也包括解决名字冲突的机制。所谓解决名字冲突,指的是处理在多个基类中可能出现的重名问题,这个问题仅在支持多重继承的语言中才会遇到。某些语言拒绝接受有名字冲突的程序,另一些语言提供了解决冲突的协议。不论使用何种语言,程序员都应该尽力避免出现名字冲突。

    <4>实现属性和服务的机制

    对于实现属性的机制应该着重考虑以下几个方面:支持实例连接的机制;属性的可见性控制;对属性值的约束。对于服务来说,主要应该考虑下列因素:支持消息连接(即表达对象交互关系)的机制;控制服务可见性的机制;动态联编。

    <5>类型检查

    程序设计语言可以按照编译时进行类型检查的严格程度来分类。如果语言仅要求每个变量或属性隶属于一个对象,则是弱类型的;如果语法规定每个变量或属性必须准确地隶属于某个特定的类,则这样的语言是强类型的。

    <6>效率

    许多人认为面向对象语言的主要缺点是效率低。事实上,如有完整类库的面向对象语言,有时能比使用非面向对象语言得到运行更快的代码。这是因为类库中提供了更高效的算法和更好的数据结构。

    <7>持久保存对象

    <8>参数化类

    所谓参数化类,就是使用一个或多个类型去参数化一个类型的机制,有了这种机制,程序员就可以先定义一个参数化的类模板(即在类定义中包含以参数形式出现的一个或多个类型),然后把数据类型作为参数传递进来,从而把这个类模板用在不同的应用程序中,或用在同一应用程序的不同部分。Eiffel语言中就有参数化类,C++语言也提供了类模板。

    <9>开发环境

    软件工具和软件工程环境对软件生产率有很大影响。由于面向对象程序中继承关系和动态联编等引入的特殊复杂性,面向对象语言所提供的软件工具或开发环境就显得尤其重要了。至少应该包括下列一些最基本的软件工具:编辑程序,编译程序或解释程序,浏览工具,调试器(debugger)等。

     

    (2)程序设计风格

    良好的程序设计风格对保证程序质量的重要性。良好的程序设计风格对面向对象实现来说尤其重要,不仅能明显减少维护或扩充的开销,而且有助于在新项目中重用已有的程序代码。

    良好的面向对象程序设计风格,既包括传统的程序设计风格和准则,也包括为适应面向对象方法所特有的概念(例如,继承性)而必须遵循的一些新准则。

    <1>提高可重用性

    面向对象方法的一个主要目标,就是提高软件的可重用性。正如本书11.3节所述,软件重用有多个层次,在编码阶段主要涉及代码重用问题。一般说来,代码重用有两种:一种是本项目内的代码重用,另一种是新项目重用旧项目的代码。内部重用主要是找出设计中相同或相似的部分,然后利用继承机制共享它们。

    • 提高方法的内聚

    • 减小方法的规模

    • 保持方法的一致性

    保持方法的一致性,有助于实现代码重用。一般说来,功能相似的方法应该有一致的名字、参数特征(包括参数个数、类型和次序)、返回值类型、使用条件及出错条件等。

    • 把策略与实现分开

    • 全面覆盖

    如果输入条件的各种组合都可能出现,则应该针对所有组合写出方法,而不能仅仅针对当前用到的组合情况写方法。

    此外,一个方法不应该只能处理正常值,对空值、极限值及界外值等异常情况也应该能够作出有意义的响应。

    • 尽量不使用全局信息

    应该尽量降低方法与外界的耦合程度,不使用全局信息是降低耦合度的一项主要措施。

    • 利用继承机制

    在面向对象程序中,继承机制是实现共享和提高重用程度的主要途径。

    有时提高相似类代码可重用性的一个有效途径,是从不同类的相似方法中分解出不同的“因子”(即不同的代码),把余下的代码作为分用方法中的公共代码,把分解出的因子作为名字相同算法不同的方法,放在不同类中定义,并被这个公用方法调用。

        程序员往往希望重用其它方法编写的、解决同一类应用问题的程序代码。重用这类代码的一个比较安全的途径,是把被重用的代码封装在类中。

    <2>  提高健壮性

        为提高健壮性应遵守以下几条准则:预防用户的误操作,不要预先限制条件,先测试后优化。

    2、面向对象测试

    一般说来,对面向对象软件的测试可分为下列四个层次进行:

    (1)算法层

    测试类中定义的每个方法,基本上相当于传统软件测试中的单元测试。

    (2)类层

    测试封装在同一个类中的所有方法与属性之间的相互作用。在面向对象软件中类是基本模块,因此可以认为这是面向对象测试中所特有的模块(单元)测试。

    (3)主题层

    测试一组协同工作的类-&-对象之间的相互作用。大体上相当于传统软件测试中的子系统测试,但是也有面向对象软件的特点(例如,对象之间通过发送消息相互作用)。

    (4)系统层

    把各个子系统组装完整的面向对象软件系统,在组装过程中同时进行测试。

    设计测试方案的传统技术,例如,逻辑覆盖、等价划分、边界值分析和错误推测等方法,仍然可以作为测试类中每个方法的主要技术。面向对象测试的主要目标,也是用尽可能低的测试成本和尽可能少的测试方案,发现尽可能多的错误。但是,面向对象程序中特有的封装、继承和多态等机制,也给面向对象测试带来一些新特点,增加了测试和调试的难度。

    七、面向对象的语言(产品)
          面向对象的语言应该具备的特征
        1.用对象而非过程(功能或算法)作为程序设计的基本逻辑构件;
        2.每个对象属于应该类(型),并为该类的一个实例;
        3.一个类可继承其它类的性质。

           面向对象的语言有:
        1.SmallTalk-76,80,(80年代下半叶)

        2.Actor(80年代下半叶)
        3.C++,Objective-C (20世纪80年代下半叶)
        4.Object Pascal, Object-Oriented Turbo Pascal,Apple ObjectPascal (80年代初开始)
        5.Eiffel (80年代上半叶) 

        6.Ada9X 
          但Microsoft Visual C++, Boland C++等都属于混合型面向对象的语言,因为它们是在原来的过程语言的基础上发展起来的,都保留了原来的数据类型,如整数、浮点数、字符以及记录等。

        几个有代表性的商品软件
        
    Microsoft Visual Basic先从软件的可视化、速成化和组件化开始的,这3化已经开始或正在形成信息与软件工艺的主流之一。
        Bland Delphi是组件软件和复合文书工艺的软件。它包含面向对象Pascal的编辑程序、查错程序、可视研制环境和工具、强大的数据库存取(BDE-Database Engine)工具;它用Object Pascal做情节描述语言。
       
     Optima++ Developer 是Sybase/Powersoft出版的可视化、速成化的研制工具。它是采用C++的一种纯可视编辑工具,用拖扔编程技术,从一组标准的和可增的控件制模板中拖出组件,将其扔进应用图表中去,并编辑其性质。它可在Windows 9X和NT下运行,它不仅是一个GUI(图形用户接口)建造程序,而且还是一个C/S(客户/服务器)数据库构造工具。 
       
     IBM的VisualAge(SmallTalk版),用一套图标来代表应用组件(对象),并提供许多标准函数(例程)、部件,供GUI配置关系数据库存取、通信、等之用。
        用户编程时,只需用鼠标把要用的部件(图标)拖扔到屏幕中的工作面内,按要求设置这些图标的缺省项和参数值,再把这些图标用线段连接起来,表示它们之间的关系和交互操作,并最后加以测试。在组装过程中,要添加复杂的计算/控件流,可用VisualAge的描述语言(Scripting Language-一种4GL)来编写。如果这还不行,VisualAge则提供SmallTalk编辑环境,以添加所需的语句。

        Digitalk(现叫ParcPlace-Digitalk)的Visual Smalltalk提供组件组装的可视研制环境和工具,用拖扔手段,可视地把组件组装成一个软件(程序),它还能自建新的组件。它最适宜研制软件雏形的OO程序设计语言。应用完成之后,使用Digitalk Smalltalk编译程序编译,其计算效率据称可增加25%,GUI效率增加了100%。
        
    Prograph CPX(跨平台)将程序面向对象结构的可视化方面做得较突出:
        -它用图标代表一个软件的组成部分,对象、类、组件全部可视化;
        -全套图标都用多面体图标,如类具有“ 方法”面和“ 属性”面;
        -能对图标加以注释,对象和类关系可用线段表示;
        -通过工具可方便地将方法加入Tools菜单;
        -既有解释程序、又有编译程序,可解除解释程序速度慢的问题。

    OO方法特点和优缺点

    1.特点

        (1)利用特定软件直接从对象客体的描述到软件结构的转换。

        (2)解决了传统结构化方法中客观世界描述工具与软件结构的不一致性。

        (3)减少了从系统分析、设计到软件模块结构之间的多次转换映射的繁杂过程。

    2.OO方法优缺点

        优点:

         (1)是一种全新的系统分析设计方法(对象、类、结构属性、方法)。

         (2)适用于各类信息系统的开发。

         (3)实现了对客观世界描述到软件结构的直接转换 ,大大减少后续软件开发量。

         (4)开发工作的重用性、继承性高,降低重复工作量。

         (5)缩短了开发周期。

        缺点:

        (1)需要一定的软件支持环境。

        (2)不太适宜大型的MIS开发,若缺乏整体系统设计划分,易造成系统结构不合理、各部分关系失调等问题。

        (3)只能在现有业务基础上进行分类整理,不能从科学管理角度进行理顺和优化。

        (4)初学者不易接受、难学。

        面向对象方法学把分析、设计和实现很自然地联系在一起了。虽然面向对象设计原则上不依赖于特定的实现环境,但是实现结果和实现成本却在很大程度上取决于实现环境。因此,直接支持面向对象设计范式的面向对象程序语言、开发环境及类库,对于面向对象实现来说是非常重要的。

    为了把面向对象设计结果顺利地转变成面向对象程序,首先应该选择一种适当的程序设计语言。面向对象的程序设计语言适合用来实现面向对象设计结果。事实上,具有方便的开发环境和丰富的类库的面向对象程序设计语言,是实现面向对象设计的最佳选择。

    良好的程序设计风格对于面向对象实现来说格外重要。它既包括传统的程序设计风格准则,也包括与面向对象方法的特点相适应的一些新准则。

    面向对象方法学使用独特的概念和完成软件开发工作,因此,在测试面向对象程序的时候,除了继承传统的测试技术之外,还必须研究与面向对象程序特点相适应的新的测试技术。在这方面需要做的研究工作还很多,目前已逐渐成为国内外软件工程界研究的一个新的热门课题。

    完毕!!!!!!!!!!!!

    大家在使用的过程中有什么好的想法或见解,都可以说出来与大家分享一下。有了自己的见解,才算是真正理解了OO吧。。呵呵。。我也不太理解,说的不对的地方,还请见谅哦~~~~~~

    展开全文
  • 面向对象考题收集

    千次阅读 2017-06-10 09:29:14
    3.下列不属于面向对象技术的基本特征的是( B )。 A. 封装性 B. 模块性 C. 多态性 D. 继承性


    1.下列不属于面向对象技术的基本特征的是( B )。 

      A. 封装性     B. 模块性     C. 多态性         D. 继承性 


    2. 面向对象程序设计将描述事物的数据与 ( C ) 封装在一起,作为一个相互依存、不可分割的整体来处理。

      A. 信息       B. 数据隐藏    C. 对数据的操作   D. 数据抽象


    3. 关于面向对象方法的优点,下列不正确的叙述是 ( C )。 

        A. 与人类习惯的思维方法比较一致     B. 可重用性好   C. 以数据操作为中心         D.可维护性好 


    4.(  D)描述了一组交互对象间的动态协作关系,它表示完成某项行为的对象和这些对象之 间传递消息的时间顺序。     

        A.对象图      B. 协作图         C. 状态图       D. 序列图  


    5.  在UML中,有四种关系,下面哪个不是(B)

      A 依赖关系   B 继承关系   C 泛化关系  D 实现关系


    6 在用例之间,会有三种不同的关系,下列哪个不是它们之间的可能的关系(D)

      A 包含(include)    B 扩展(extend)   C 泛化( generalization)  D 关联(connect)


    7.(  D )为编程人员提供了重复利用程序资源的一种途径,使编程人员可以扩充和完善旧的程序以适用新的需求。  

         A. 封装机制     B. 抽象机制     C. 多态机制      D. 继承机制 


    8. 下面哪个选项中 ( C )不是序列图中的基本元素。  

      A.对象       B. 生命线      C. 泳道            D.消息


    9 在面向对象程序设计语言中,对象之间通过( A)方式进行通信。
    A.消息传递
    B.继承
    C.引用
    D.多态


    10 以下关于好的面向对象程序设计语言的叙述中,不正确的是(C)。
    A.应该支持被封装的对象
    B.应该支持类写实例的概念
    C.应该支持通过指针进行引用
    D.应该支持继承和多态


    11 如果要表示待开发软件系统中软件组件和硬件之间的物理关系,通常采用UML中的(B)。

    A.组件图
    B.部署图
    C.类图
    D.网络图

    12 在UML用例图中,参与者表示(A )。
    A.人、硬件或其他系统可以扮演的角色
    B.可以完成多种动作的相同用户
    C.不管角色的实际物理用户
    D.带接口的物理系统或者硬件设计


    以下关于UML状态图的叙述中,不正确的是(1 C)。对下图的描述正确的是(2 D)。


    (1)A.用于描述一个对象在多个用例中的行为
    B.用于某些具有多个状态的对象而不是系统中大多数或全部对象
    C.用于描述多个对象之间的交互
    D.可以用于用户界面或控制对象
    (2)A.ON是一个并发状态
    B.因为此状态图中没有终止( final)状态,所以此图是无效的
    C.play、stop和rew是动作
    D.ON是超状态


    15. 一个设计得好的OO系统具有(B)

    A. 低内聚、低耦合的特征 C. 高内聚、高耦合的特征

    B. 高内聚、低耦合的特征 D. 低内聚、高耦合的特征


    16.构成对象的两个主要因素是(A)。

    A. 属性和服务

    B. 标识和内容

    C. 继承和多态

    D. 消息和封装


    17. 计算机(Computer)由中央处理器、内存、软盘、硬盘、显示器、键盘、鼠标等组成。那么Computer类和其他类(CPU、RAM、FloppyDrive、HardDisk、Monitor、Keyboard、Mouse)之间的关系是:(D)

    A. 泛化关系(Generalization) C. 包含关系(Inclusion)

    B. 实现关系(Realization) D. 聚集关系(Aggregation)


     18. 软件产品在需求发生变化、运行环境发生变化或发现软件产品本身的错误或不足时进行相应的软件更新的难易程度叫做软件的(  A  )。          

        A. 可维护性    B. 可复用性    C. 兼容性        D. 正确性


    19 某一基类有构造函数A(),析构函数~A(),其派生类B的构造函数析构函数分别为B(),~B(),程序说明B的对象b时,下列说法正确的是( B)

    A. 开始时,先调用 A(),再调用B(),结束时,先调用~A(),再调用~B()

    B. 开始时,先调用 A(),再调用B(),结束时,先调用~B(),再调用~A()

    C. 开始时,先调用 B(),再调用A(),结束时,先调用~A(),再调用~B()

    D. 开始时,先调用 B(),再调用A(),结束时,先调用~B(),再调用~A()第二部分非选择题

    20 下面说法不正确的是( D)

    A. 一个对象通过继承可以获得另一个对象的特性

    B. 面向对象就是将世界看成是由一组彼此相关并能相互间通信实体,即对象组成的

    C. 面向对象要求程序员集中于事物的本质特征,用抽象的观点看待程序

    D. 同一函数为不同的对象接受时,产生的行为是一样的,这称为一致性


    21  关于成员函数特征,下述描述中,(A )是错误的。

    A. 成员函数一定是内联函数

    B. 成员函数可以重载

    C. 成员函数可以设置参数的缺省值

    D. 成员函数可以是静态的


              22、( D)方法以原型开发思想为基础,采用迭代增量式开发,发行版本小型化,比较适合需求变化较大或者开发前期对需求不是很清晰的项目。

    A.信息工程


    B.结构化


    C.面向对象


    D.敏捷


    23、用例(Use case)用来描述系统对事件作出响应时所采取的行动。用例之间是具有相关性的。在一个“订单输入子系统”中,创建新订单和更新订单都需要核查用户帐号是否正确。用例“创建新订单”、“更新订单”与用例“核查客户帐号”之间是(A )关系。


    A.包含(include) C.分类(classification)


    B.扩展(extend) D.聚集(aggregation)


    24-25、面向对象的设计模型包含以(B )表示的软件体系结构图,以(D)表示的用例实现图,完整精确的类图,针对复杂对象的状态图和用以描述流程化处理的活动图等。 (3)A.用例图 (4)A.部署图


    B.包图 B.包图


    C.协同图 C.协同图


    D.顺序图 D.顺序图


    26、以下关于软件构件及其接口的叙述,错误的是(C )。


    A.构件是软件系统中相对独立且具有一定意义的构成成分 B.构件在容器中进行管理并获取其属性或者服务 C.构件不允许外部对所支持的接口进行动态发现或调用 D.构件可以基于对象实现,也可以不基于对象实现 


    27、UP是( A)。


    A.面向对象统一开发过程 C.软件成熟度模型


    B.面向对象分析与设计 D.统一建模语言

      

      28. 面向对象方法的多态性是指(   C)。
            A. 一个类可以派生出多个特殊类
            B. 一个对象在不同的运行环境中可以有不同的变体
            C. 针对一消息,不同的对象可以以适合自身的方式加以响应
            D. 一个对象可以是由多个其他对象组合而成的    


    29.(  A )不是面向对象系统所包含的要素。
       A.重载    B.对象  C.类    D.继承


    30.重载函数在调用时选择的依据中,(  D  )是错误的。
    A.参数个数   B. 参数的类型   C.参数的顺序    D. 函数类型


    31.采用函数重载的目的在于( D   )。
    A.实现共享   B. 减少空间 C.提高速度    D.使用方便,提高可读性


     32 执行者(Actor)与用例之间的关系是(C)


     A 包含关系  B 泛化关系  C 关联关系 D 扩展关系



    33  构件图的组成不包括(C)


    A 接口 B 构件 C 发送者  D 依赖关系


     34 拆箱是关于: (B)


    A 值类型到引用类型的转换  B 引用类型到值类型的转换
    B 引用类型到引用类型的转换  D 值类型到值类型的转换


    35 下面异常说法不正确的是(D)


    A try/catch 块为基本引发异常组合
    B 在捕获异常时,可以有多个catch块
    C 无论异常是否发生, finally块总会执行
    D try块和finally不能连用


    36.所有在函数中定义的变量,连同形式参数,都属于( )
    A.全局变量 B.局部变量
    C.静态变量 D.寄存器变量


    37、如果float f=4.2F;Float g=new Float(4.2F); Double d=new Double(4.2);则下列选项正确的是( B )。   

     A、f==g   B、f==g.floatValue()   C、d==f   D、d.equals(f) 


    38、下列二维数组定义中错误的是( A )。 

      A、int a[][]=new int[][];   B、int []a[]=new int[10][10];   C、int a[][]=new int[10][10];   D、int [][]a=new int[10][10];  1

    39、关于下列语句哪个答案是正确的( D )。   

     System.out.println(4|7);   

     A、4   B、5   C、6   D、7


    40. 根据下面的代码,可以确定类A与类B之间存在( A )关系。


    public class A {


    private B theB;


    public void aMethod(){ theB.doSomthing(); }


    }


    A 关联 B 泛化 C 实现 D 包含


    41. 下列语句序列执行后,k 的值是C  int i=10, j=18, k=30;  switch( j - i ) {  case 8 : k++;  case 9 : k+=2;  case 10: k+=3;  default : k/=j;  }  A.31        B.3       C.2       D.33


    42. 使用UML进行关系数据库的( B )时,需要设计出表达持久数据的实体类及其联系,并把它们映射成为关系数据库表(Table)、视图(View)等。

    A. 业务Use Case模型设计 B. 逻辑数据模型设计

    C. 物理数据模型设计 C. 物理实现设计




    判断题


      1. 协作图中的消息必须要有消息顺序号。( true )

      2.在画类图时,属性或操作如果是public的,可以用“+”表示,protected用“#”表示,private用 “-”表示。

    3.协作图是对象图的扩展。              ( 对 )
    4.只有状态图采用泳道。                ( 错 )
    5.部署图一般把节点分成处理器和外部软件。            ( 错 )

    抽象类中不可以有非抽象的方法。   (错)

    12

    for 

    语句中的循环体不能为空。

     

     

    12

    for 

    语句中的循环体不能为空。

     

     

    7、for 语句中的循环体不能为空。( 错 )


    8、break语句也可以用于if体内,它可退出if语句。(错  ) 


    多选题目


    1、 下面关于构造方法的说法正确的是(  AB)
    A. 构造方法不能被继承 //只能被调用
    B. 构造方法不能被重写 //
    C. 构造方法不能被重载 //能
    D. 构造方法不能声明为private  //错


    2 面哪些属于UML的图  ( A, B)


    A、用例图 B、类图 C、结构图 D、流程图


    3 关于封装的说法正确的是(A D ) 


    A、封装实现了信息隐藏 
    B、封装使对象与外界隔绝 
    C、封装使类不可见 
    D、封装将对象的属性和操作结合在一起 


    4  下列关于状态图说法中,不正确的时候(ABD)


    A 状态图是UML中对系统的静态方法进行建模的五种图之一。


    B 状态图是活动图的一个特例,状态图中的多数状态是活动状态。


    C 活动图和状态图是对一个对象的生命周期进行建模,描述对象随时间变化的行为。


    D 状态图强调对有几个对象参与的活动过程建模,而活动图更强调对单个反应型对象建模。


    5  组件图用于对系统的静态实现视图建模,这种视图主要支持系统部件的配置管理,通常可以分为四种方式来完成,下面哪些是其中之一。(ACD)


     A 对源代码建模   B 对事物建模   C 对物理数据库建模  D 对可适应的系统建模



    6 关于协作图的描述,下列正确的是(ACD)


    A 协作图作为一种交互图,强调的是参加交互的对象的组织。


    B 协作图是顺序图的一种特例。


    C 协作图中有消息流的顺序号。


    D 在ROSE工具中,协作图可在顺序图的基础上按 “F5”键自动生成。



    7 对于构造函数,下列哪个叙述是正确的? (ABD)


    A 构造函数也允许重载
    B 子类无条件集成父类的无参构造函数
    C 子类不允许调用父类的构造函数
    D 在同一个类中定义重载构造函数可以相互调用。

    展开全文
  • R语言面向对象指南

    千次阅读 2015-09-21 21:53:00
    面向对象指南:这一章主要介绍怎样识别和使用 R 语言的面向对象系统(以下简称 OO)。R 语言主要有三种 OO 系统(加上基本类型)。本指南的目的不是让你精通 R 语言的 OO,而是让你熟悉各种系统,并且能够准确地区分...
  • 对C++面向对象的编程的理解

    千次阅读 2019-01-16 18:05:06
    面向对象方法历经了30多年的研究和发展,已经日益成熟和完善,应用也越来越深入和广泛,现其已经发展为主流的软件开发方法。 本节主要介绍面向对象方法的优点以及它的一些基本概念。 2.3.1面向对象方法的优点(1)与...
  • 摘 要 自80年代后期以来,相继出现了多种面向对象开发方法,文章主要介绍了其中六种典型的面向对象开发方法,并对它们进行了比较。UML的出现意味着开发方法统一化、标准化的新发展,标志着软件自动化的进程又...
  • 系统分析与设计方法---面向对象的分析与设计

    万次阅读 多人点赞 2018-09-14 20:26:32
     面向对象方法是一种非常实用的软件开发方法,它一出现就受到软件技术人员的青睐,现已成为计算机科学研究的一个重要领域,并逐渐成为软件开发的一种主要方法。面向对象方法以客观世界中的对象为中心,其分析和设计...
  • Java实现面向对象编程

    万次阅读 2018-07-17 16:18:06
    1.1用面向对象设计电子宠物系统... 14 1.1.1为什么使用面向对象... 14 1.1.2使用面向对象进行设计... 15 1.2通过创建对象实现领养宠物功能... 17 1.2.1创建类的对象... 17 1.2.2构造方法及其重载... 23 1.2.3...
  • 类和面向对象习题

    万次阅读 2017-04-13 21:49:31
    3.4 精选习题 ...1.下列不属于面向对象编程的特性的是( )。 A.封装 B.继承 C.抽象 D.多态 2.(*)下述概念中不属于面向对象的是( )。 A.对象、消息 B.继承、多态 C.类、封装 
  • 面向对象练习题

    千次阅读 2016-12-15 17:42:15
    Java面向对象练习题 一、填空题 1.如果一个方法不返回任何值,则该方法的返回值类型为void。 2.访问修饰符有public、protected、private 3.一般Java程序的类主体由两部分组成:一部分是成员属性,另一部分是成员...
  • 目录 第 4 章 Java面向对象程序设计 一.单项选择题 二. 填空题 三.简答题 四.程序阅读题 ...五....一....A....B....C....D....2.下列不属于面向对象编程的三个特征的是 A.封装 B.指针操作 C.多态性 D.继承 3....
  • 面向对象设计原则

    千次阅读 2014-04-09 18:10:06
    和设计模式相关的是设计原则。...面向对象设计模式描述了面向对象设计过程中、特定场景下、类与相互通信的对象之间常见的组织关系,包括它们的角色、职责、协作方式几个方面。  从编程语言来看,各种面向对象
  • 面向对象思想强大之处是,我们可以继续划分类,比如,前面说的人类可以属于动物类,那么本属于人类的男人或女人,也可以属于动物类。 面向对象三大特性是什么?封装、继承、多态。 首先,我们先...
  • 面向对象编程思想

    万次阅读 2014-06-24 21:18:46
    面向对象是一种新兴的程序设计方法,或者说它是一种新的程序设计范型,其基本思想是使用对象,类,继承,封装,消息等基本概念来进行程序设计。 它是从现实世界中客观存在的事物(即对象)出发来构造软件系统,并...
  • 面向对象的开发方法(Object Oriented,OO) 面向对象的开发方法(Object Oriented,OO)认为是好文章吧,拿来与大家分享一下(转载) 现在每个程序员都会说:OO思想,OO开发,呵呵,是真的理解了嘛?看看下面的文章...
  • Python面向对象(一)

    千次阅读 2015-09-29 19:15:53
    Python也是一门面向对象的编程语言。下面就让我们走进Python的面向对象编程世界。但是在正式进行python的面向对象编程时,得先了解一些Python中类的知识。 类是Python实现支持继承的新种类的对象的部件,也是Python...
  • Java面向对象测试题

    千次阅读 2019-12-06 21:42:08
    一、选择题 针对以下题目,请选择最符合题目要求的答案。针对每一道题目,所有答案都选对,则该题得分,所选答案错误或能选出所有答案,则该题...B. DriverManager类调用getConnection()方法,创建连接对象并...
  • 理解面向对象

    2007-07-13 11:51:00
    为什么要学习面向对象语言?我们知道,世界上的万事万物都可以看作是属于不同类别的个体,或称之为对象,这些对象之间彼此存在着直接或间接的关联。面向对象的设计思想恰好也是以类、类与类之间的关系作为分析问题的...
  • perl面向对象编程-方法的调用

    千次阅读 2009-03-09 14:16:00
    Perl的方法定义提供任何特殊语法,但规定方法的第一个参数为对象或其被引用的包。Perl有两种方法:静态方法和虚方法。静态方法第一个参数为类名,虚方法第一个参数为对象的引用。方法处理第一个参数的方式决定了它...
  • 面向对象复习总结

    千次阅读 2016-12-07 21:11:27
    面向对象方法是一种运用对象、类、继承、封装、聚合、关联、消息、多态性等概念来构造系统的软件开发方法。 基本思想 从现实世界中客观存在的事物出发来建立软件系统 强调直接以问题域(现实世界)中的事物...
  • 面向对象软件工程知识点

    千次阅读 2016-07-11 11:46:28
    面向对象软件工程知识点  1.封装是指把对象的(A)结合在一起,组成一个独立的对象。 A.属性和操作 B.信息流 C.消息和事件 D.数据的集合 2.状态图和活动图建立了UML面向对象开发过程中的对象动态(B)...
  • 面向对象的开发方法(Object oriented,OO)认为是好文章吧,拿来分享一下(转载) 面向对象的开发方法(Object oriented,OO)  从事软件开发的工程 师们常常有这样 的体会:在软件开发过程中,使用者会不断地...
  • 面向对象的分析

    千次阅读 2011-04-11 08:27:00
     面向对象(Object Oriented,OO)是当前计算机界关心的重点,它是90年代软件开发方法的主流。面向对象的概念和应用已超越了程序设计和软件开发,扩展到很宽的范围。如数据库系统、交互式界面、应用结构、应用...
  • 面向对象:将程序的变量以及功能整合到一起成为:对象,程序的流程是在对象生成后决定的,后期拓展程序只需要更改对象即可,理解:解决问题需要哪些对象 但并不是说开发程序一定要用面向对象编程思想来进行开发,...
  • 原文链接:面向对象设计—类和对象** 1. 面向对象程序设计的基本概念 Java是一种面向对象的编程语言。面向对象编程,英文是Object-Oriented Programming,简称OOP。 那什么是面向对象编程? 面向对象其实是现实世界...
  • Python面向对象详解

    万次阅读 2011-10-25 13:05:02
    提到面向对象,总是离开几个重要的术语:多态(Polymorphism),继承(Inheritance)和封装(Encapsulation)。Python也是一种支持OOP的动态语言,本文将简单阐述Python对面向对象的支持。 在讨论Python的OOP之前...
  • 面向对象测试题

    千次阅读 2020-01-08 16:09:18
    粗体标出的字体即为答案。 一、填空题 每空1分共15分 1.如果一个方法返回任何值,则该方法的返回值类型为 void 。...4. 抽象 方法是一种仅有方法声明,没有具体方法体和操作实现的方法,该方法必须在 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,720
精华内容 10,288
关键字:

下列不属于面向对象方法的是