Java基础知识——面向对象技术

详情参看:面向对象技术

  • 面向对象与面向过程的区别
    • 面向对象:当今软件开发方法的主流方法之一,它是把数据及对数据的操作方法放在一起,作为一个相互依存的整体,即对象。对同类对象抽象出共性,即类,类中的大多数数据,智能被本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。
    • 面向过程:是一种以时间为中心的开发方法,就是自顶向下顺序执行,逐步求精,其程序结构是按功能划分为若干个基本模块,这些模块形成一个树状结构,各模块之间的关系也比较简单,在功能生相对对立,每一个模块内部一般都是由顺序、选择和循环3中基本结构组成,其模块化实现的具体方法是使用子程序,而程序流程在写程序时就已经决定。
    • 两种方法不同之处
      • 出发点不同
        • 面向对象方法:用符合常规思维的方法来处理客观世界的问题,强调把问题域的要领直接映射到对象及对象之间的接口上。
        • 面向过程方法:强调过程的是过程的抽象化与模块化,它是以过程为中心构造或处理客观世界问题的。
      • 层次逻辑关系不同
        • 面向对象方法:用类的层次结构来实现类之间的继承和发展。
        • 面向过程方法:用模块的层次结构概括模块或模块之间的关系与功能,把客观世界的问题抽象成计算机可以处理的过程。
      • 数据处理方式与控制程序方式不同
        • 面向对象方法:将数据与对应的代码封装成一个整体,原则上其他对象不能直接修改其数据,即对象的修改只能有自身的成员函数完成,控制程序方式上通过“事件驱动"来激活和运行程序。
        • 面向过程方法:直接通过程序来处理数据,处理完毕后,即可显示处理结果,在控制程序方式上是按照设计调用或返回程序,不能自由导航,各模块之间存在着控制与被控制、调用与被调用的关系。
      • 分析设计与编码转换方式不同
        • 面向对象方法:贯穿于软件生命周期的分析、设计及编码中,是一种平滑的过程,从分析到设计再到编码是采用一致性的模型表示,即实现的是一种无缝连接。
        • 面向过程方法:强调分析、设计及编码之间按照规则进行转换,贯穿于软件生命周期的分析、设计及编码中,实现的是一种有缝的链接。
  • 面向对象特征
    • 抽象
      • 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。
      • 抽象包括:过程抽象和数据抽象。
    • 继承
      • 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。
      • 对象的一个新类可以从现有的类中派生,这个过程称为类继承。
      • 派生类可以从它的基类那里继承方法和实例变量,并且派生类可以修改或添加新的方法使之更符合特殊的需要。
    • 封装
      • 封装是指将客观事物抽象成类,每个类对自身的数据和方法实行保护。
      • 类可以把自己的数据和方法只让可信的类或对象操作,对不可信的进行信息隐藏。
    • 多态
      • 多态是指允许不同类的对象对同一消息做出响应。
      • 多态包括参数化多态和包含多态。
      • 多态性语言具有灵活、抽象、行为共享、代码共享等优势,很好地解决了应用程序函数同名问题。
  • 组合和继承的区别
    • 组合和继承是面向对象中两种代码复用的方式。
    • 组合是指在新类里面创建原有类的对象,重复利用已有类的功能。
    • 继承允许设计人员根据其他类的实现来定义一个类的实现。
    • 组合和继承都允许在新的类中设置子对象,只是组合是显式的,而继承是隐式的。
    • 组合和继承存在着对应关系:组合中的整体类和继承中的子类对应,组合中的局部类和继承者的父类对应。
    • 继承关系 : is-a 组合关系:has-a
    • 如何选择继承和组合?
      • 除非两个类之间是“is-a”关系,否则不要轻易用继承,不要单纯为了实现代码的重用而使用继承,因为过多使用继承会破坏代码的可维护性,当父类被修改时,会影响所有子类,从而增加程序的维护难度和成本。
      • 不要仅仅为了实现多态而使用继承,如果类之间没有“is-a”的关系,可以通过实现接口与组合的方式来达到相同的目的。
      • 采用接口与组合的方式比采用继承的方式具有更好的可扩展性。
    • 由于Java只支持单继承。在Java中,能使用组合就尽量不要使用继承。
  • 多态的实现机制
    • 多态表示当同一操作作用在不同对象时,会有不同的语义,从而产生不同的结果。
    • 多态主要有两种表现方式
      • 方法的重载overload
        • 它是指一个类中有多个同名方法,但这些方法有着不同的参数,因此在编译时就可以确定到底调用哪个方法,它是一种编译时多态。
        • 重载可以被看做一个类中的方法多态性。
      • 方法的覆盖override
        • 子类可以覆盖父类的方法,因此同样的方法会在子类与父类中有着不同的表现形式。
        • 在Java语言中,基类的引用变量不仅可以指向基类的实例变量,也可指向子类的实例变量。同样,接口的引用变量也可以指向实现类的实例变量。
        • 程序调用的方法在运行期才动态绑定(绑定指的是将一个方法调用和一个方法主体连接起来),就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
        • 通过这种动态绑定到的方法实现了多态。 通过方法覆盖实现的多态也可以被称为运行时多态。
      • 此外,只有类中的方法才有多态性的概念,类中的成员变量没有多态性的概念。成员变量的值取父类还是子类并不取决于创建对象的类型,而是取决于所定义变量的类型,这是在编译期间确定的。
      • Java中提供了哪两种用于多态的机制
        • 编译时多态和运行时多态。编译时多态是通过方法的重载实现的,运行时多态是通过方法的覆盖(子类覆盖父类)实现的
package base2;

class Base{
	public Base() {
		g();
	}
	public void g() {
		System.out.println("Base g()");
	}
	public void f(){
		System.out.println("Base f()");
	}	
}

class D extends Base{
	@Override
	public void f() {
		System.out.println("D f()");
	}
	@Override
	public void g() {
		System.out.println("D g()");
	}
}

public class Test {
	public static void main(String[] args) {
		Base b=new D();
		/**
		 * 在执行Base b=new D();语句时,会调用Base类的构造函数
		 * ,而在其构造函数中,执行了g()方法,由于Java语言的多态特性,
		 * 此时会调用D类的g()方法,而非父类的g()方法,因此会输出D g()
		 * 由于实际创建的是D 类的对象,后面的方法调用都会调用子类D 的方法。
		 */
		b.f();
		b.g();
	}

}
运行结果:
D g()
D f()
D g()
package base.java;

class Base{
	public int i=1;
}

class D extends Base{
	public int i=2;
}

public class Test {
	public static void main(String[] args) {
		Base b=new D();		
		System.out.println(b.i);
		/**
		 * 运行结果:1
		 * 只有类中的方法才有多继承的概念,类中的成员变量没有继承的概念。
		 */
	}
}
  • 重载和覆盖的区别
    • 重载是在一个类中多态性的一种表现,是指在一个类中定义了多个同名的方法,他们或有不同的参数个数或有不同的参数类型。
    • 使用重载需注意
      • 重载是通过不同的方法参数来区分的,例如不同的参数个数、不同的参数类型或不同的参数顺序。
      • 不能通过方法的访问权限、返回值类型和抛出的异常类型进行重载。
      • 对于继承来说,若基类访问权限是private,那么不能在派生类对其进行重载;如果派生类也定义了一个同名函数,这只是一个新方法,不会达到重载的效果。
    • 覆盖是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同的作用。
    • 使用覆盖时需注意
      • 派生类中的覆盖方法必须要和基类中被覆盖的方法有相同的函数名和参数。
      • 派生类中的覆盖方法的返回值要与基类相同。
      • 派生类中的覆盖方法所抛出的异常必须和基类(或是其子类)种被覆盖的方法所抛出的异常一致。
      • 基类中被覆盖的方法不能为private,否则其子类只是定义了一个方法,没有对其进行覆盖。
    • 重载与覆盖的区别
      • 覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。
      • 覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
      • 覆盖要求参数列表相同;重载要求参数列表不同。
      • 覆盖关系中,调用方法体是根据对象的类型来决定;而重载是根据调用时的参数表与形参表来选择方法体的。
  • 抽象类与接口
    • 如果一个类中包含抽象方法,那么这个类就是抽象类。
    • 接口就是指一个方法的集合,接口中的所有方法都没有方法体。
    • 抽象类和接口都是支持“抽象类”定义的两种机制。
    • 抽象类可以声明方法的存在而不去实现它,被声明为抽象的方法不能包含方法体。在实现时,必须包含相同的或者更低的访问级别。
    • 抽象类在使用的过程中不能被实例化,但可以创建一个对象使其指向具体子类的一个实例。
    • 抽象类的子类为父类中的所有抽象方法提供具体的实现,否则他们都是抽象类。
    • 接口可以被看成抽象类的变体。
    • 接口中的所有方法都是抽象的,可以通过接口来间接地实现多重继承。
    • 接口中的成员变量都是static final类型。
    • 由于抽象类可以包含部分方法的实现,因此,在一些场合下,抽象类优于接口。
    • 抽象类与接口相同点
      • 都不能被实例化
      • 接口的实现类或者抽象类的子类都只有实现了接口或抽象类中的方法后才能被实例化。
    • 抽象类与接口的不同点
      • 接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。
      • 接口需要实现(implements),但抽象类只能被继承(extends)。一个类可以实现多个接口,但只能单继承,可以使用接口间接实现多继承的目的。
      • 接口强调特定功能的实现,其设计理念是“has-a”关系;而抽象类强调所属关系,设计理念是“is-a”关系。
      • 接口中定义的变量默认为public static final,只能够有静态的不能被修饰的数据成员,而且,必须给其赋初值,其所有成员方法都是public、abstract的,而且只能被这两个关键字修饰;抽象类根据自己的数据成员变量,也可有非抽象的成员方法,而且,抽象类中的成员变量默认为default,也可定义为其他。抽象类中的抽象方法不能用private、static、synchronized、native等访问修饰符修饰,同时方法必须以分号结尾,并且不带花括号。所以,当功能需要累积时,用抽象类;不需要时,用接口。
      • 接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适合用于日后重新对里面的代码进行修改。
    • 抽象类多用于在同类事物中有无法具体描述的方法的场景,当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类;
    • 接口多用于不同类之间,定义不同类之间的通信规则。
    • 接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的main方法。
    • abstract只能修饰类和方法,不能修饰属性。
  • 内部类
    • 静态内部类
      • 不依赖于外部类实例而被实例化
      • 不能与外部类有相同的名字
      • 不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法(包括私有类型)
    • 成员内部类
      • 可以自由地引用外部类的属性和方法,无论是静态的还是非静态的。
      • 它与一个实例绑定在了一起,不可以定义静态的属性和方法。
      • 只有在外部类实例化后才能实例化。
      • 非静态内部类中不能有静态成员。
    • 局部内部类
      • 指的是定义在代码块中的类,是内部类最少使用的一种类型。
      • 局部内部类像局部变量一样,不能被Public、protected、private及static修饰,只能访问方法中定义为final类型的局部变量。
    • 匿名内部类
      • 它是一种没有类名的内部类,不使用关键字class、extends、implements,没有构造函数,他必须继承extends其他类或实现其他接口。匿名内部类的好处是代码更加简洁、紧凑,但带来的问题是易读性下降。
      • 他一般应用于GUI编程中实现事件处理。
      • 在使用匿名内部类时,需要牢记6个原则
        • 不能有构造函数
        • 不能定义静态成员、方法和类
        • 不能是public、protected、private、static
        • 只能创建匿名内部类的一个实例
        • 一个匿名内部类一定是在new的后面,这个匿名类必须继承一个父类或实现一个接口。
        • 因为匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
  • 如何获取父类的类名
    • getClass().getName()
    • 在子类中得到父类的名字
      • 可以通过Java的反射机制,使用getClass().getSuperclass().getName()
  • this与super的区别
    • 在Java语言中,this用来指向当前实例对象,作用是用来区分对象的成员变量与方法的形参
    • super可用来访问父类的方法或成员变量。当子类的方法或成员变量与父类有相同名字时也会覆盖父类的方法或成员变量,要想访问父类的方法或成员变量只能通过super关键字来访问。
  • 当子类构造函数需要显示调用父类构造函数时,super()必须为构造函数中的第一条语句。
package base2;

class Base{
	public Base() {
		System.out.println("Base");
	}
}

class Sub extends Base{
	public Sub() {
		System.out.println("Sub");
		super();
	}
}

public class Test3 {

	public static void main(String[] args) {
		Base s=new Sub();
	}

}
/**
 * 编译错误。
 * 当子类构造函数需要显示调用父类构造函数时,
 * super()必须为构造函数中的第一条语句。
*/




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Baymax_wyl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值