首页 > 编程 > Java > 正文

Java面向对象

2019-11-10 21:34:39
字体:
来源:转载
供稿:网友

问题: 继承和组合 接口,实际上比抽象类更加抽象,它是最高层次的抽象。接口中的所有方法都是抽象方法,不会有任何实现方面的代码

C语言是一种面向过程的语言,在现代软件开发过程中面临一些难以解决的问题,比如程序规模大到一定程度后难以团队开发和维护等。于是人们从C语言的结构体中得到了启示,将其逐渐扩展到类,最终形成了面向对象的,新的编程方法。但是面向过程的语言是基础,面向对象的中的方法还是面向过程的形式。

面向对象的是核心是,以类来组织代码,以对象来组织数据。

java语言是一种非常受欢迎的面向对象的开发语言。类可以看做一种自定义的数据类型。从概念上来讲,类是某一类事物的抽象,所谓抽象,就是指抽出象的部分,即提取共同点。对象则是类的具体存在。程序使用类的构造器来创建对象。

面向对象除了类和对象的概念外,还有三大特征:封装、继承和多态。Java提供了PRivate、protected和public三个访问控制符来实现封装,提供了extends关键字来让子类继承父类,,,,

1、类和对象

类和对象是面向对象设计语言中的两个重要概念。 除了8种基本类型之外,类可以当做一种自定义数据类型,可以使用类来定义变量,这种类型的变量称为引用变量。 private String name = “Tom”; private School s = new School();

1.1 定义类

[修饰符] class 类名{ 零到多个成员变量 零到多个构造方法 领导多个普通方法 } 修饰符可以是public、final、abstract或者完全省略 类名的首字母要大写

static修饰的成员不能调用非static修饰的成员 成员变量用于定义该类或者类的实例所包含的状态数据,方法定义了该类的功能,构造器用于构造该类的实例,构造器是类创建对象的根本途径,若一个类没有构造器则无法创建实例,所以Java默认为类提供了一个无参构造,而一旦程序员为一个类提供了构造器,默认构造器即失效。

成员变量的定义格式: [修饰符] 类型 成员变量名 [=默认值]; 修饰符:可以省略,也可以是public、protected、private、static、final,其中前三个互斥,只能出现一个,但可以与static、final组合起来修饰成员变量。 如定义常量常使用: public static final double PI = 3.1415926;

类型:类型可以使用8种基本类型和引用类型。

方法的定义格式: [修饰符] 方法返回值类型 方法名(形参列表) { // 零到多条可执行语句组成的方法体 } 修饰符:可以省略,也可以是public、protected、private、static、final、abstract,其中前三个互斥,只能出现一个,final和abstract互斥、但他们可以与static组合起来修饰方法。 返回值类型:可以是8种基本类型或者引用类型,若没有返回值则必须使用void来声明没有返回值。

static是个特殊的关键字,可以用来修饰成员变量、成员方法、内部类和初始化块,表示它属于这个类本身,而不是属于该类的单个实例。只是表示这种归属的。

构造器是个特殊的方法,它的定义格式: [修饰符] 构造器名(形参列表){ //零到多条可执行性语句组成的构造器执行体 } 修饰符:可以省略,也可以是public、protected、private其中之一 构造器名: 必须和类名相同 构造器的返回值类型总是当前类,无须定义返回值类型,也不能使用return语句,如果定义了,编译器不会报错,只会把这个所谓的构造器当做普通方法来处理。

2、对象的创建

Person p = new Persion();

3、对象、引用和指针

4、对象的this引用

Java提供了this关键字,它总是指向调用该方法的对象。 根据this出现位置的不同,this作为对象的默认引用有两种情形: 1. 构造器中引用该构造器正在初始化的对象; 2. 在方法中引用调用该方法的对象。

this关键字的最大作用就是让类中的一个方法,访问该类里的另一个方法或者成员属性。 典型例子,dog类中的,run方法调用同类中的jump方法,使用this来调用。也可以省略这个this,即一个方法访问该类中定义的其他方法和成员变量时加不加this前缀的效果是一样的。但有种特殊情况,成员方法中的局部变量和类的成员变量重名时,若要调用类的成员变量,则必须使用this前缀。 使用static修饰的成员变量和方法是不能用this来调用的。

this可以作为方法的返回值,则可以多次连续调用同一个方法,从而使代码更加简洁,类似jQuery的。缺点是模糊了语义。

public class Tree{ public int age; public Tree grow(){ age++; return this; }}Tree t = new Tree();t.grow().grow().grow();syso(t.age);

2、方法详解

方法是类或对象的行为特征的抽象,从功能上来看,方法完全类似于传统面向过程设计语言中的函数。 但是他们也有明显的区别: 在结构化编程语言中,函数是一等公民,整个软件由一个个函数组成,在面向对象编程语言中,类才是一等公民。Java中的方法不能独立存在,所有的方法都必须定义在类中。

2.1 方法的所属性

方法不是独立存在的实体,只能作为类和对象的附属,主要体现在: 1. 方法不能独立定义,只能在类中定义 2. 从逻辑意义上来看,方法要么属于类本身,要么属于类的一个对象 3. 永远不能独立执行方法,执行方法必须使用类或对象作为调用者。

2.2 方法的参数传递机制

Java方法的参数传递方式只有一种:值传递。 所谓值传递,就是将实际参数值的副本传入方法内,而参数本身不会受到任何影响。这个传入的参数,不管遇到什么更改都不会改变外部原有的情况,操作的都是这个副本。 例如: 一个swap(int a, int b)方法,将传入的两个值进行交换,则外部的a,b不会受到任何影响。 进入一个方法,即进入了这个方法独有的方法栈。

Java对于引用类型的参数传递,一样采用的是值传递方式。 不过这个传递的值是地址,地址是值传递,它指向的是对象。所以实际操作的是对象,看起来是引用传递,其实还是值传递。

2.3 形参个数可变的方法

从JDK1.5 开始,Java允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参。如果在定义方法时,在最后一个形参的类型后增加三点(…),则表明该形参可以接受多个参数值,多个参数值被当成数组传入。

public class Varages{ public static void test(int a, String... books){ for(String tmp: books){ System.out.println(tmp); } } public static void mian(String[] args){ test(5, "Java", "Spring", "Oracle"); }}

形参个数可变的参数其实就是个数组参数,即 public static void test(int a, String… books); public static void test(int a, String[] books); 区别是,调用更简洁,直接罗列,不用写成数组的形式,test(5, “Java”, “Spring”, “Oracle”); 如果写成数组的形式,则调用时必须 test(5, new String[]{“Java”, “Spring”, “Oracle”}); 但是,数组形式的参数可以位于形参列表的任意位置,但是个数可变的形参只能处于形参列表的最后,也就是说,一个方法中最多只能有一个长度可变的形参。

2.4 递归方法

一个方法体内,调用它自身,称为方法递归。它会重复执行某段代码,这个重复执行无须循环控制。 递归有一条最重要的规定,递归一定要向已知方向递归。

递归是非常有用的,如果我们希望便利某个路径下的所有文件,但这个路径的深度是位置的,就可以使用递归来实现这个需求。

2.5 方法重载

方法重载,即方法名相同,参数列表不同。方法的其他部分,如方法返回值类型、修饰符等,与方法重载无关。 Java中不能使用返回值类型作为区分方法重载的依据。因为Java调用时可以忽略返回值,即int f(){}和void f(){}两个方法,都可以使用f()调用,无法区分调用的是那个。

即,Java程序中唯一确定一个方法,需要同时满足三个要素 1. 调用者,方法的所属者,可以是类,也可以是对象 2. 方法名 3. 形参列表

3、成员变量和局部变量

Java中根据变量位置的不同,可以将变量分为两大类,成员变量和局部变量。他们的运行机制存在较大的差异。

3.1 成员变量和局部变量的定义

成员变量分为,类成员变量和实例成员变量 类成员变量随着类的存在而存在,实例成员变量随着实例的存在而存在,所以类成员变量的作用域更大

局部变量分为,形参、方法局部变量、代码块局部变量,共同点是作用域都仅限于方法的区域,方法结束即失效

成员变量在类加载时会默认初始化,但是局部变量除形参外,都必须显示初始化。

3.2 成员变量的初始化和内存中的运行机制

当系统加载类或创建类的实例时,系统自动为成员变量分配内存空间,并指定初始值。 类初始化后,系统自动回类创建一个类对象。

Person p = new Person(); p.name = “Tom”; 存储变化的示意图

3.3 局部变量的初始化和内存中的运行机制

局部变量定义后,必须经过显示初始化才能使用,系统不回位局部变量执行初始化,即也不会为这个变量分配内存空间,直到程序为这个变量赋初始值时,系统才会为局部变量分配内存,并将初始值保存到这块内存中。

与成员变量不同,局部变量不属于任何类或对象,因此它总保存在其所在方法的栈内存中。 如果局部变量是8种基本类型之一,则直接将这个变量值保存到对应的内存中,如果局部变量是一个引用类型的变量,则这个变量里存放的是地址,通过该地址引用到该变量实际引用的对象或数组。 栈内存中的变量无需垃圾回收,随方法或代码块的运行结束而结束。

3.4 变量的使用规则

什么时候使用成员变量,什么时候使用局部变量呢? 当我们定义一个成员变量时,会将其放到堆内存中,成员变量的作用域将扩大到类或对象的存在范围。这有两个坏处: 1. 增大了变量的生存时间,这将导致更大的内存开销; 2. 扩大了变量的作用域,不利于提高程序的内聚性。

所以,我们应该有限制的使用成员变量,即当: 1. 需要定义的变量是用于描述类或对象的信息的,例如,如果是人类的眼睛,每个人对象都是相同的,则应该定义为类的成员变量,如果是人的身高体重等个体性强的信息,则应该定义为对象成员变量。 2. 如果需要以一个变量来保存该类或实例运行时的状态信息,例如定义棋盘数组用于其后保存棋盘的运行状态信息。 3. 某个信息需要在类的多个方法之间进行共享的

使用局部变量时,也应该尽可能的缩小局部变量的作用范围,局部变量的作用范围越小,它在内存中停留的时间就越短,程序的运行性能就越好,因此,能用代码块局部变量的地方,就坚决不要使用方法局部变量。

4、隐藏和封装

4.1 理解封装

封装指的是讲对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的访问和操作。

封装是对客观世界的模拟,例如人的年龄外部是无法操作的,只能随着时间的流逝增加。 使用封装的目的是: 1. 隐藏类的实现细节 2. 使用者只能通过特点的方法来访问,在这个方法中,我们可以通过逻辑来对访问进行限制 3. 便于修改,提高代码的可维护性,例如接口

为了实现良好的封装,需要考虑: 1. 将对象的成员变量和实现细节隐藏起来,不允许外部直接访问; 2. 把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作。

即,把该隐藏的隐藏起来,把该暴露的暴露出来。 实现封装,需要通过Java提供的访问控制符来实现。

4.2 使用访问控制符

访问控制符,用来控制一个类的成员是否可以被其他类访问

范围 public protected default private
同一个类中 * * * *
同一个包中 * * *
子类中 * *
全局范围内 *

对于局部变量而言,其作用域就是它所在的方法,不可能被其他类访问,因此不能使用访问控制符来修饰。

对于外部类而言,只能有public和默认两种访问控制级别,因为外部类没有其所在类的内部、所在类的子类两个范围,因此private和protect的访问控制符对外部类没有意义。 外部类的默认访问控制级别,只能被同一个包中的其他类使用。 若一个Java源文件中的所有类都没有使用public修饰,则这个源文件的文件名可以是一切合法的文件名,但如果这个Java源文件中定义了一个public修饰的类,则这个源文件的文件名必须与public修饰的类的类名相同。一个Java源文件中只能有一个public修饰的类。

访问控制符使用的原则: 1. 类中绝大部分成员变量都应该使用private修饰,只有一些static的类似全局变量的成员变量才可能考虑使用public修饰。成员方法中,不需要对外提供调用的方法,也应该使用private修饰。 2. 如果某个类主要用作其他类的父类,该类中包含的大部分方法仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰。 3. 希望暴露给其他类自动调用的方法应该使用public修饰。例如类的构造器。

4.3 package、import和import static

世界上这么多类,肯定会有重名的类,如何解决呢? 我们可以在类名前增加一个前缀来限定这个类,Java引入了包(package)机制,提供了类的多层命名空间,用于解决类的命名冲突、类文件管理等问题。 在Java源程序的第一个非注释行放置如下格式代码: package packageName; 则当前Java源文件中定义的所有类都属于这个包,位于包中的每个类的完整类名都应该是包名和类名的组合,如果其他人需要使用该包下的类,也应该使用包名加类名的组合。

Java的包机制需要2个方面的保证: 1. 源文件中使用package语句指定包名 2. class文件必须放在对应的路径下

包名应该全小写

import语句用于导入刀哥包层次下的类。 可以导入包下的指定类名的类,或者使用*导入包下的所有类,但不能导入包下子包中的类。 如果不导入指定的类,则使用这些类时需要使用全类名。

Java默认为所有源文件导入java.lang包下的所有类,因此使用String、System类时都无需使用import语句来导入这些类。

静态导入使用 import static语句,静态导入可以导入指定类的单个静态成员变量、方法和全部静态成员变量、方法。 使用import可以省略包名,使用import static则连类名都可以省略了。 import static java.lang.Math.*; System.out.println(PI);

4.4 Java的常用包

Java的核心类都放在java这个包及其子包下,Java扩展的许多类都放在javax包及其子包下。

java.lang,包含了Java语言的核心类,如String、Math、System和Thread类等,这个包下的类无须使用import语句导入,系统会自动导入java.util,包含了Java的大量工具类/接口和集合框架类/接口,如Arrays和List、Set等java.net,包含了一些Java网络编程相关的类/接口java.io,包含了一些Java输入/输出编程相关的类/接口java.text,包含了一些Java格式化相关的类java.sql,包含了Java进行JDBC数据库编程相关的类/接口java.qwt,包含了抽象窗口工具集的相关类/接口,可用来构建图形用户界面java.swing,包含了Swing图形用户界面的相关类/接口,可用于构建平台无关的GUI程序

5、深入构造器

构造器是个特殊的方法,用于创建实例时执行初始化,及时使用工厂模式、反射等方式创建对象,其实质仍然依赖于构造器,因此Java类必须包含一个或以上的构造器。

5.1 使用构造器执行初始化

构造器最大的用出就是在创建对象时执行初始化。 当创建一个对象时,系统为这个对象的成员变量进行默认初始化,这种默认初始化将所有基本类型的成员变量都设为0,把所有引用类型的成员变量都设置为null。

构造器是创建对象的重要途径,通过new关键字调用构造器时,构造器也确实返回了该类的对象,但这个对象并不是完全由构造器负责创建的。 实际上,当程序员调用构造器时,系统会先为该对象分配内存空间,并为这个对象执行默认初始化,这个对象已经产生了。这些操作在构造器执行之前就都完成了,只是这个对象还不能被外部程序访问,只能在构造器中通过this来引用。当构造器的执行体执行结束后,这个对象作为构造器的返回值被返回,通常会赋值给另一个引用类型的变量,从而让外部程序可以访问该对象。

一旦程序员提供了自定义的构造器,系统就不在提供默认的构造器,如果用户希望保留无参数的构造器,可以提供多个构造器,这就是构造器的重载。

5.2 构造器的重载

同一个类中有多个构造器,多个构造器的形参列表不同,即称为构造器重载。

6、类的继承

继承是实现软件复用的重要手段,Java的继承只有单继承,即每个类只有一个直接父类(间接的可能有很多)。

6.1 继承的特点

Java的继承通过extends关键字来实现,实现继承的类称为子类,被继承的类称为父类。父类和子类的关系,犹如水果和苹果的关系。父类的范围要比子类大,是一种特殊的子类。子类是父类的扩展。

修饰符 class SubClass extends SuperClass{ //类的定义}

子类是父类的扩展,也叫继承,因为子类获得了父类的全部成员变量和方法,但是子类不能获得父类的构造器。 Java摒弃了C++中难以理解的多继承特性。

若定义一个Java类时并未显式指定这个类的直接父类,则这个类默认扩展java.lang.Object类,Object类是所有类的父类,要么是直接父类要么是间接父类。所有类都可以调用Object类的方法。

6.2 重写父类的方法

欢迎使用Markdown编辑器写博客

本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦:

Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传LaTex数学公式UML序列图和流程图离线写博客导入导出Markdown文件丰富的快捷键

快捷键

加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl + Q插入链接 Ctrl + L插入代码 Ctrl + K插入图片 Ctrl + G提升标题 Ctrl + H有序列表 Ctrl + O无序列表 Ctrl + U横线 Ctrl + R撤销 Ctrl + Z重做 Ctrl + Y

Markdown及扩展

Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ]

使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个链接等,详细语法参考帮助?。

本编辑器支持 Markdown Extra ,  扩展了很多好用的功能。具体请参考Github.

表格

Markdown Extra 表格语法:

项目 价格
Computer $1600
Phone $12
Pipe $1

可以使用冒号来定义对齐方式:

项目 价格 数量
Computer 1600 元 5
Phone 12 元 12
Pipe 1 元 234

定义列表

Markdown Extra 定义列表语法:项目1项目2定义 A定义 B项目3定义 C

定义 D

定义D内容

代码块

代码块语法遵循标准markdown代码,例如:

@requires_authorizationdef somefunc(param1='', param2=0): '''A docstring''' if param1 > param2: # interesting print 'Greater' return (param2 - param1 + 1) or Noneclass SomeClass: pass>>> message = '''interpreter... prompt'''

脚注

生成一个脚注1.

目录

[TOC]来生成目录:

1类和对象1 定义类2对象的创建3对象引用和指针4对象的this引用2方法详解1 方法的所属性2 方法的参数传递机制3 形参个数可变的方法4 递归方法5 方法重载3成员变量和局部变量1 成员变量和局部变量的定义2 成员变量的初始化和内存中的运行机制3 局部变量的初始化和内存中的运行机制4 变量的使用规则4隐藏和封装1 理解封装2 使用访问控制符3 packageimport和import static4 Java的常用包5深入构造器1 使用构造器执行初始化2 构造器的重载6类的继承1 继承的特点2 重写父类的方法欢迎使用Markdown编辑器写博客快捷键Markdown及扩展表格定义列表代码块脚注目录数学公式UML 图离线写博客浏览器兼容

数学公式

使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com.

行内公式,数学公式为:Γ(n)=(n−1)!∀n∈ℕ。块级公式:

x=−b±b2−4ac‾‾‾‾‾‾‾‾√2a

更多LaTex语法请参考 这儿.

UML 图:

可以渲染序列图:

Created with Raphaël 2.1.0张三张三李四李四嘿,小四儿, 写博客了没?李四愣了一下,说:忙得吐血,哪有时间写。

或者流程图:

Created with Raphaël 2.1.0开始我的操作确认?结束yesno关于 序列图 语法,参考 这儿,关于 流程图 语法,参考 这儿.

离线写博客

即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。

用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。

博客发表后,本地缓存将被删除。 

用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。

注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱

浏览器兼容

目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。IE9以下不支持IE9,10,11存在以下问题 不支持离线功能IE9不支持文件导入导出IE10不支持拖拽文件导入

这里是 脚注内容. ↩
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表