学习内容
3.1、面向对象基本概念
3.2、类
3.3、成员方法
3.4、对象
3.5、面向对象特征
3.6、接口
3.7、包
学习产出
3.1 面向对象基本概念
面向对象是一种程序设计方法,或者说它是一种程序设计规范,其基本思想是使用对象、类、继承、封装、消息等基本概念来进行程序设计。Java是一种存粹的面向对象的程序设计语言。
3.1.1.对象的基本概念
对象是系统中用来描述客观事物的一个实体,是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。
现实世界中的对象有两个共同特征:形态和行为。
举例:(张三拜访李四)
//张三拜访李四
面向对象:
1.找出事件当中的参与者,并抽象为某种类别:主人 客人
2.找出参与者各自在事件中的动作:
主人:ask() openDoor()
客人:knock() reply() sitdown()
3.编程时,定义2个类:Master() Guest(),分别把各自的动作(方法),定义到各自的类里面
4.定义第三个类Tester,在main()中通过调用2个对象的方法来描述拜访过程。
Master.java
public class Master {
public void ask() {
System.out.println("主人问,谁呀?");
}
public void openDoor() {
System.out.println("主人开门,让张三进屋。。");
}
}
Guest.java
public class Guest {
public void knock() {
System.out.println("张三敲门。。");
}
public void reply() {
System.out.println("回答我是张三");
}
public void sitdown() {
System.out.println("张三进屋坐下。。");
}
}
Tester.java
public class Tester {
public static void main(String[] args) {
Master m = new Master();
Guest g = new Guest();
g.knock();
m.ask();
g.reply();
m.openDoor();
g.sitdown();
}
}
运行效果:
3.1.2. 类的基本概念
对象是指具体的事物,而类是指一类事物。
由类来确定具体对象的过程称为实例化,即类的实例化结果就是对象,而对一类对象的抽象就是类。
类用class作为它的关键词。
//当我们需要通过汽车类来创建一个轿车对象,并使用它的刹车行为方法时,则要用下米娜的格式进行实例化
汽车 轿车 = new 汽车();
轿车.刹车();
3.2 类
类和对象是Java的核心和本质。定义类和建立对象是Java编写的主要任务。
3.2.1 类的定义
1.类的一般形式
类由类声明和类体组成,而类体又由成员变量和成员方法组成。
public class 类名 //类声明
{
成员变量;
成员方法; //类体
}
//举例
public class Hello //类声明
{
static String str; //成员变量
public static void main(String[] args)
{
st = "hello world";
System.out.println(str); //成员方法
}
}
2.类声明
类声明由四部分组成:类修饰符、类关键字class、声明父类、实现接口。
一般形式为:
[public][abstract][final] class 类名 [extends 父类名] [implements 接口列表]
{
.
.
.
}
- 类修饰符
类修饰符含义如下:
- public:声明了类可以在其他类中使用。
- abstract:声明了这个类为抽象类,即这个类不能被实例化。
- final:声明该类不能被继承,不能有子类。
-
类的关键词
声明类的关键字。通常情况下,类名要用大写字母开头,并且类名不能用阿拉伯数字开头。 -
声明父类
extends为声明该类的父类,表明该类是其父类的子类。一个子类可以从它的父类继承变量和方法。(单继承)
class SubClass extends 父类名
{
.
.
}
- 实现接口
接口是一个特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
implements 接口1,接口2,....
3.2.2 成员变量和局部变量
成员变量和局部变量主要是根据在程序中所处的位置决定的。
class Data
{
int x,y; //x、y为成员变量
public void sum()
{
int s; //s为局部变量
s = x + y;
}
}
如果局部变量与成员变量相同,则成员变量被屏蔽。
class Data
{
int x = 12,y = 5; //此时成员变量x=12将被屏蔽
public void sum()
{
int x =3;
int s;
s = x + y;
}
}
如果我们在sum内部确实需要需要是用成员变量,可以使用关键词this来引用当前对象,它的值是调用该方法的对象。
class Data
{
int x = 12,y = 5; //此时成员变量x=12将被屏蔽
public void sum()
{
int x =3;
int s;
s = this.x + y; //这里将使用成员对象X
}
}
3.3 成员方法
在java中,必须通过方法才能完成对类的属性操作。成员方法只能在类的内部声明加以实现。一般在类体中声明成员变量之后再声明方法。
3.3.1 方法的定义
方法的定义类似于类的定义,由方法声明和方法体两部分组成。
返回类型 方法名(数据类型1 参数1 ,数据类型2 参数2,。。。) //方法声明
{
.....(局部变量定义);
.....(方法功能实现); //方法体
return(返回值);
}
例:
public static void main(String[] srgs)
{
String str = "hello world !";
System.out.println(str);
}
- 方法不允许嵌套定义,即不允许一个方法的定义放在另一个方法的定义中。
- 在方法的定义中,方法的类型是该方法返回值的数据类型。
3.3.2 方法的调用
我们把调用其他方法的方法称为主调方法,被其他方法调用的方法称为被调方法。
方法的调用格式:
函数名(实际参数1,实际参数2,。。。。);
单个参数的调用:
import javax.swing.*;
public class Exanmple
{
public static void main(String[] args)
{
int sum = mysum(100); //调用mysum方法
JOptionPane.showMessageDialog(null,"1+2+3+4+...+100 = "+ sum);
System.exit(0);
}
static int mysum(int n)
{
int i,s = 0;
for(i = 1;i<=n;i++) //形参n以100进行计算
s = a + i;
return s; //计算结果返回给被调函数
}
}
多个参数的调用同理!!!!
调用过程中参数是通过实参向形参传值的。
这里我看书上给了一个传值的过程图,看着略显复杂,其实真的不难理解!
这里引入了一个堆栈的概念:(主调方法为实参赋值,将实参值存放到内存中专门存放临时变量的区域中。这块存储区域称为堆栈。)
3.3.3 方法重载
方法重载是指多个方法享有相同的名字,但这些方法的参数必须不同,或者是参数的个数不同,或者是参数的类型不同,返回类型不能用来区分重载的方法。
这里如果单纯地看这段文字多少有些干涩,我们通过一个例子来理解:
举例:(两个数求和)
public class Tester {
public static void main(String[] args) {
Tools t = new Tools();
int x0 = t.add(3,5);
System.out.println("参数个数为2时,和为" + x0);
int x1 = t.add(3,5,6);
System.out.println("参数个数为3时,和为" + x1);
}
}
public class Tools {
int add(int a , int b) //参数个数为2
{
return a + b;
}
int add(int a,int b,int c) //参数个数为3
{
return a + b + c;
}
}
此时运行结果如图:
通过单步调试我们会发现,程序运行时会根据我们参数的个数在相同名字的方法里选择合适的一个!!
重载使得程序的实现方式变得很简单,只需要一个方法名,就可以根据不同的参数个数选择该方法的不同版本。
3.3.4 构造方法
构造方法是一个特殊的方法,主要用于初始化新创建的对象。构造方法的方法名要与类名相同,且无返回值。
注意:这里说的构造方法无返回值,并不是要在构造方法名前加上void ,构造方法名是不能有void的,如果在构造方法名前加了void,系统就不会自动调用该方法了。
一个类可以创建多个构造方法,当类中包含多个构造方法时,将根据参数的不同来决定要用哪个构造方法来初始化新创建对象的状态,达到方法重载的目的。
举例:(求长方形的面积)
public class Rectangle {
int width,length;
Rectangle(){
//构造方法,没有参数,方法名与类名相同
length = 2;
width = 2;
}
Rectangle(int len,int wid){
//构造方法,带有参数
length = len;
width = wid;
}
int getArea()
{
return length*width;
}
}
public class Tester {
public static void main(String[] args) {
Rectangle rect_1 = new Rectangle();
Rectangle rect_2 = new Rectangle(6,4); //应用构造方法创建实例对象
int area_1 = rect_1.getArea();
int area_2 = rect_2.getArea();
System.out.println("长方形的面积为:" + area_1);
System.out.println("长方形的面积为:" + area_2);
}
}
运行结果:
&&:在一个类的程序中,也可以没有定义构造方法,则Java系统会认为是定义了一个缺省构造方法,缺省构造方法是无任何内容的空方法。当编写类时,只有在需要进行一些特别初始化的场合,才需要定义构造方法。
直接给一个书上的例子:
/*缺省构造方法构造长方体类*/
class Box
{
double width,height,depth;
double volume() //计算长方体体积
{
width = 10;
height =10;
depth =10;
return width*height*depth;
}
}
public class Example
{
public static void main(String[] args)
{
Box box = new Box; // 应用缺省方法创建实例对象
double v;
v = box .volume();
System.out.println("长方体体积为:" + v);
}
}
3.4 对象
通过前面我们知道类是一个抽象的概念,而对象是类的具体化。
一个对象的生命周期包括三个阶段:创建、使用和释放。
需要注意的是:对象是引用类型,因此,对象名这个变量,其值是一个长整型(代表了另外一个内存单元的首地址)。对象实体对应的内存在首地址指向的另一地方。
1.对象的创建
类名 对象名 = new 类名([参数列表])
这一表达式隐含三部分:对象声明 实例化 初始化
/*对象声明*/
类名 对象名;
/*实例化*/
对象名 = new 构造方法();
2.对象的使用
访问对象成员变量的格式:
对象.成员变量;
调用对象成员方法的格式:
对象名.方法名([参数列表]);
3.5 面向对象特性
Java语言中有三个典型的面向对象的特性:封装性、继承性、多态性。
3.5.1 封装性
封装性就是把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节。
在Java语言中,对象就是对一组变量和相关方法的封装,其中变量表明了对象的态度,方法表明了对象具有的行为。通过对象的封装,实现了模块化和信息隐蔽。
1.修饰符
为了对类对象封装,通过对类成员修饰符 施以一定的访问权限,从而实现类中成员的信息隐藏 。
类体定义的格式:
class 类名
{
[变量修饰符] 类型 成员变量名;
[方法修饰符] 返回类型 方法名(参数){
.....}
}
2.访问权限的限定
在类体成员定义的修饰符可选项中,提供了4种不同的访问权限。它们是private、default、protected 和 public。
- private
在一个类中被限定为private的成员,只能被这个类本身访问,其他类无法访问。如果一个类的构造方法声明为private,则其他类不能生成该类的一个实例。 - default
在一个类中不加任何访问权限限定的成员属于缺省的(default)访问状态,可以被这个类本身和同一个包中的类所访问。 - protected
在一个类中被限定为protected的成员,可以被这个类本身、它的子类(包括同一个包中以及不同包中的子类)和同一个包中的所有其他的类访问。 - public
在一个类中限定为public的成员,可以被所有的类访问。
3.5.2 继承性
继承性是面向对象程序中两个类之间的一种关系,即一个类可以从另一个类继承状态和行为。
被继承的类称为父类(超类),继承的类称为子类。
Java不支持多重继承!!!
1.子类的定义
class 父类
{
....
}
class 子类 extends 父类
{
.....
} //继承实现了代码复用
举例:
这里我们以同时输出老师和学生的信息为例:
//原始思路:定义老师和学生两个类和各自的信息,主类调用输出
//利用继承思路:我们定义一个公共的Person类,用老师和学生的类继承该Person类
代码展示:
//Tester.java
public class Tester {
public static void main(String[] args) {
Teacher t = new Teacher();
Student s = new Student();
t.name = "张老师";
t.age = 35;
t.mobile = "15571569574";
t.Output();
s.name = "李小华";
s.age = 20;
s.mobile = "17255617524";
s.Output();
}
}
//Person.java
public class Person {
String name;
int age;
String mobile;
void Output()
{
System.out.println("全部信息为:" + name + "-" + age + "-" + mobile);
}
}
//Teacher.java
public class Teacher extends Person {
//继承Person类
}
//Student.java
public class Student extends Person {
//继承Person类
}
运行截图:
分析:从上面的这个例子不难看出,当我们在某些类中有相同的操作,比如输出相同的信息,我们不需要逐个类进行操作,可以给这些类一个父类,让它们继承父类的属性,这样一来就减少了代码量,提高工作效率。
创建子类对象时,Java虚拟机首先执行父类的构造方法,然后再执行子类的构造方法。
从本程序的运行结果可以看出:
(1)父类的构造方法也会被子类继承,且Java虚拟机首先执行父类的构造方法。
(2)在多继承的情况下,创建子对象时,将从继承的最上层父类开始,依次执行各方法。
2.成员变量的隐藏和方法的重写
子类通过隐藏父类的成员和重写父类的方法,可以把父类的状态和行为改变为自身的状态和行为。
calss A //父类
{
int x;
void setX(){
x = 0;
}
}
class B extendas A //子类
{
int x; //隐藏父类的变量x
void setX(){
//重写父类的方法,此时将调用子类自己的方法
x = 5;
}
}
3.super关键字
关键字super用来实现对父类成员的访问。
三种使用情况:
- 访问父类被隐藏的成员变量或者方法。
- 调用父类中被重写的方法
- 调用父类的构造方法
4.this关键字
this表示某个对象,可用于构造方法和实例方法,但不能用于类方法。
- 用于构造方法时,代表调用该构造方法所创建的对象
- 用于实例方法时,代表调用该方法的当前对象
this.当前类的成员方法();
或者
this.当前类的成员变量
public class A {
int x = 100;
A(){
this.x = 1000;
}
A(int a){
this.x = 10000;
}
}
public class Tester {
public static void main(String[] args) {
A a = new A();
A aa = new A(88);
System.out.println(a.x); //输出结果为1000
System.out.println(aa.x); //输出结果为10000
}
}
3.5.3 多态性
多态是指一个程序中同名的方法共存的情况,有时需要利用这种重名的现象来提供程序的抽象性和简洁性。
在Java中,多态性体现在两个方面,由方法重载实现的静态多态性和方法重写实现的动态多态性。
3.5.4 其他修饰符的用法
(1)final关键字
可放到类、成员变量、方法前面,限定它们。
a. final int X=100; // 放到成员变量的类型前面, 定义一个常量X
b. final int add(int a, int b){
... } //放到方法声明前面,此方法不能被子类重写
c. final class Person{
... } //放到class前,此类不能被继承,只能独立使用此类
(2)static关键字
在java语言中,成员变量和成员方法可以进一步分为两种:类成员和实例成员。
用关键字static修饰的变量或方法称为类变量和类方法。反之称为·实例变量或实例方法。
static 类型 变量名;
static 返回类型 方法名(参数)
{
.
.
.
}
如果在声明的时候用static来修饰,则声明的是静态变量和静态方法。
调用时不需要实例化!!!!
(3)类成员与实例成员的区别
可以将 类变量、类方法,看作是该类的所有对象(一个类,可以new出多个对象出来)共享使用的。
实例变量、实例方法则不同,由一个类new出多个对象,每个对象有自己的变量、方法,互不干扰、互不“来往”。
(4)abstract关键字(抽象类)
用abstract修饰一个类的时候,这个类叫做抽象类。
abstract class 类名 //定义抽象类
{
成员变量;
方法(); //定义普通方法
abstract 方法(); //定义抽象方法
}
抽象类是专门设计用来让子类继承的类!
抽象类的特点总结如下:
- 类体中,可以定义普通方法,也可以定义抽象方法;也可以只有普通方法,没有抽象方法;也可以只有抽象方法,没有普通方法;
- 抽象类中的抽象方法是只有方法声明,没有代码实现的空方法;
- 抽象类不能被实例化;
- 若某个类包含了抽象方法,则该类必须被定义为抽象类;
3.6 接口
3.6.1 接口的定义
接口是抽象类的一种,只包含常量和方法的定义,而没有变量和具体方法的实现,且其方法都是抽象方法。
接口的用处:
- 通过接口实现不相关类的相同行为,而无需考虑这些类之间的关系;
- 通过接口指明了多个类需要实现的方法;
- 通过接口了解对象的交互界面,而无需了解对象所对应的类。
[public] interface 接口名 [extends 父接口名]
{
.
.
.
}
说明:接口可以多重继承 ------ 一个接口可以继承多个接口,接口之间逗号分隔。
3.6.2 接口的实现
接口必须是由类来实现(换句话说,类会使用接口—在声明中,用implements语句实现接口,一个类可以实现多个接口,逗号分隔多个接口)
例如:已定义接口 IPrintable, IBrowserable, IShowable, 当某个类要实现这3个接口时,语法为: public class Article implements IPrintable, IBrowserable, IShowable { … }
接口中就相当于定义了一套规则—>定义功能(空方法),那些实现接口的类,根据自己的需要来对每个规则进行填充(代码)!
3.6.3 接口的应用
这里我们定义一个报警接口,调用此接口实现报警门和报警灯。
public interface Alarm1 {
//报警接口
public void Alarm(); // 抽象方法
}
public class Alarmdoor implements Alarm1{
//实现接口的报警门类
public static void main(String[] args) {
Alarmdoor door = new Alarmdoor();
door.Alarm();
}
public void Alarm() {
//编写接口抽象方法的具体代码
System.out.println("门报警,滴滴滴滴。。。。");
}
}
public class Alarmlight implements Alarm1{
//实现接口的报警灯类
public static void main(String[] args) {
Alarmlight light = new Alarmlight();
light.Alarm();
}
public void Alarm() {
System.out.println("灯亮了,闪闪闪闪。。。");
}
}
3.7 包
包的作用:用来管理类。 想想C语言中的 math.h , stdio.h 这些头文件。我们一看就能知道,math.h 中肯定提供了很多跟数学运算有关的函数; stdio.h 中肯定提供了跟 I/O操作有关的函数。
3.7.1 java系统包
同样地,Java中,通过包来管理一些相关的类。例如,Java中常用的系统包定义如下。通过包来分门别类管理所有的类。如果我们编程时需要使用到系统的包,就必须通过import导入到当前类文件中。
3.7.2 用户自己创建包
在类的第一行语句,使用package 包名; 语句来定义自己的包。例如:
package course.wsyu.edu.cn; //只能在源码文件的最上面
public class Student{
// 学生类归于包 course.wsyu.edu.cn
...
}
3.7.3 包的引用
在其他类A中使用别的包中的类所定义的方法,要通过
import 包名.类名 ; 或 import 包名.* ; 来引用包。
这样在类中就可以使用该包中各个类所定义的方法。
例如我们前期的例子中,当在main方法中使用Scanner类时,必须在文件第一行写上:
import java.util.*; // *表示 所有类,但实际运行中,只会加载 Scanner类
或 import java.util.Scanner; // 表示只引用Scanner类,因此也只加载它
3.7.4 压缩文件jar包
- 如果想把一个项目中的几个类(工具类),提供给另外一个类B来使用,怎么做呢?
将这几个类的 .class 文件放在一个目录下;
- 利用 jar.exe 程序,把这几个 .class 打包成一个 .jar 压缩文件;
- 将.jar文件,放到 jdk安装目录下的 jre\lib\ext 目录下;
- 在你的类B文件中,使用 import 包名.类名 ; 然后在B类的方法中,就可以使用 .jar 压缩包中的类及方法。
- 如何来压缩多个 .class 文件为 一个 .jar 文件呢?
-
编写一个 Manifest.mf清单文件,将要打包的类名加入该文件中,例如:
Manifest-Version: 1.0
Main-Class: Class1 Class2 -
压缩为.jar文件, 命令行执行以下命令,生成MyLib.jar 压缩包
Jar cfm MyLib.jar Manifest.mf Class1.class Class2.class -
将应用程序也可以压缩为一个 jar 文件
Java程序其实就是 .class 文件, 它不能双击运行;为了让一个Java程序能够双击就运行,可以把所有该项目的.class都打包为一个jar文件,然后就可以双击这个jar文件执行程序。
当要压缩多个类时,可以在清单文件Manifest.mf 中,只写主类(含有main() 方法的那个类)的类名即可;
在使用jar打包时,使用 *.class 来代表所有的.class。例如:
Jar cfm MyLib.jar Manifest.mf *.class
需要注意: 如果机器上安装了 winrar 解压缩软件,那么不能双击这个 jar 程序要运行它。可以编写一个批处理文件,如abc.bat 文件,里面只有一行:
Javaw -jar MyLib.jar
之后,双击运行 abc.bat 即可。
总结
距离上一次整理java笔记有半个月了,中间间隔这么久的原因有二,一是这一章节的内容相较于前面更加难懂,课后需要消化的内容比较多 ,所以整理起来比较慢,二是最近又在做一个STM32的小项目(目前已经完成,准备出一篇博客),这就导致了时间不是很充裕,趁着今天周末,加班加点整理了这一章节的知识~
如有不足,欢迎各位大佬指正~