面向对象编程基础
1.1 面向对象概述
在程序开发初期,大家使用的是结构化开发语言,也就是面向过程(opp),但随着市场需求剧增,软件的规模也越来越大,结构化语言的弊端也暴露出来。
开发周期无休止的拖延,软件质量也越来越差。
为了更好的适应市场,有人就开始以另一种开发思想引入程序中,也就是面向对象的开发思想(oop)。
面向对象思想是人类最自然的一种思考方式,他将所有预处理的问题抽象为对象,同时了解这些对象具有哪一些对应的属性以及行为,以解决这些对象面临的一些实际问题,面向对象设计实质上就是对现实世界的对象进行建模操作。或者说把现实世界的操作虚拟到程序中去
1.2 对象
对象,是一个抽象概念,英文称为“Object”,表示存在的事物。通俗的来说就是世间万物皆对象!现实世界中肉眼可见的一种事物都是对象,对象是事物存在的实体,例如:人、手机、电脑。为了大家能简单的理解,只要现实世界中看得到的实物都是一个对象。
1.2.1 对象的组成
一个实体(对象)可以划分两个部分,一个是描述外观和功能。那么在程序里关于实体(对象)描述外观的称为“属性”;实体(对象)的功能称之为“行为”或“方法”,也就是实体(对象)执行的动作。例如:人的性别是描述这个实体(对象)的,人能行走也能吃饭和学习是执行的动作。
实体(对象)由属性和行为组成,也就是实体(对象)的外观和功能。
1.3 类
类是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体被称之为类(简单的理解也可以是分类)。例如:大雁群就可以看做是大雁类,因为每一只大雁都有相同的嘴、翅膀和爪等外貌特性;同时每一只大雁也会睡觉、飞行、觅食等行为。所以就可以进行分类用程序角度来说的话这一群大雁就是一个大雁类。而大雁群中的每一只大雁都是大雁类的一个对象。
从上面两张流程图我们知道大雁群中的每一只大雁都具备一样的外观描述和行为(功能),那么我们就可以把这个实体(对象)称之为这个分类下的对象或者实体。
总结:类可以理解为分类,是抽象的。而对象就是实体,可以看得到摸得着的。
1.3.1 OPP程序设计特点简单介绍
面向对象程序设计具有以下三个通用特点:
√封装性
√继承性
√多态性
a).封装
封装是面向对象编程的核心思想。也就是将对象的特征和行为封装起来,其载体就是类,类通常会隐藏其实现细节,这就是封装的思想。也就是说现实生活中的物品或商品你只要负责使用就ok,其他的你可以不管。例如:使用手机打电话,只要你打通电话就行,具体内部怎么实现无需知道。
总结:程序中采用封装的思想主要是保证了类内部数据结构的完整性和安全性,使用该类的用户不能轻易的直接操作次数据结构,只能操作类允许公开的数据。这样一来就避免了外部操作对内部数据的影响,提高了程序的可维护性。
b) 继承
继承是每一门计算机语言不可少的机制,主要作用就是利用继承机制使新建的类可以建立在原有类的基础之上。在使用或者重写原有类的行为或者功能(程序里叫成员方法)以及访问原有类的特征(也就是类的成员变量)。我们可以称新类为子类,原有类为父类。举个例子:如果类A是类B的父类,而类B是类C的父类,那么也可称类C是类A的子类,类C是从类A基础而来。同时在java中,关于类的继承是单一继承的,也就是说,一个子类只能拥有一个父类,一个父类可以有多个子类。总而言之,继承是在代码中实现重复利用的重要手段,子类通过继承,复用父类特征和行为的同时又添加了子类特有的特征和行为。
c) 多态
将父类对象应用于子类的特征就是多态。多态通俗理解就是多种形态,但每一个实体(对象)还是具备了父类的特征和行为。
2.类与对象
上面我们认识类的时候就已经讲过,类是我们封装实体(对象)的外观特征(属性)和行为的载体,也就是说这个实体(对象)有哪一些外观描述和功能都可以在类里面进行封装描述
2.1 类的声明
语法:
public class 类名称
{
//类的主体...
}
注意:
- 如果类文件中只有一个类时,文件名必须与类名保持一致;
- 一个java文件中只能有一个public类;
- 如果类文件中不止一个类,文件名必须与public类名一致;
- 如果文件中不止一个类,而且没有public类,文件可与任意类名一致;
java类名的命名规则:
- 类名应该以下划线(_)或者字母开头,最好以字母开头;
- 第一个字母最好大写,如果类名由多个单词组成,则每个单词的首字母最好都大写;
- 类名不能为java中的关键字,例如:String、this、double、int等;
- 类名不能包括任何嵌入的空格或点号,以及除了下划线(_)和美元符号($)字符之外的特殊符号。
2.2 a 成员变量
java中实体(对象)的特征(属性)也称之为成员变量,成员变量的定义和普通变量定义是一样的。
数据类型 变量名称 [ = 值 ];
注意:代码中的[ = 值]表示可选内容,也就是说定义变量时可以为其赋值也可以不赋值。
我们来举一个例子,例如鸟类==》Bird类,成员变量对应于类对象属性,鸟都有翅膀、爪子、嘴巴、羽毛...而这一些都是描述鸟的外观也就是对象的属性,所以Bird应该有四个成员变量:wing、claw、beak、feather。
//定义一个Bird鸟类
public class Bird{
String wing; //翅膀
String claw; //爪子
String beak; //嘴巴
String feather; //羽毛
}
分析:上面 代码使用关键字class定义类,类名是Bird,同时在Bird类中定义了4个成员变量,成员变量的类型可以设置java中合法的数据类型,说到底成员变量和普通变量是一样的,成员变量也可以设置初始值,也可以不设置初始值。不设置初始值就会有一个默认值。
数据类型 | 默认值 | 详细说明 |
float、double | 0.0 | 浮点零 |
char | '' | 空格字符 |
boolean | false | 逻辑符 |
引用类型,如:String | null | 空值 |
int、byte、short、long | 0 | 0值 |
上面是我们在定义类时使用的一些数据类型以及对应的默认值
2.2 b 成员方法
2.2.1 成员方法的定义
成员方法对应类对象(实体)的行为或者功能,主要是用来定义类可执行的操作,行为或者功能就是一系列语句组成的代码块。
语法:
[权限修饰符] [返回值类型] 方法名 ([参数类型 参数名]){
//方法体--> 一系列代码
return 返回值;
}
分析:
- 权限修饰符可以是private、public、protected中的任意一个,也可以不写,主要来控制方法(行为)的访问权限。
- 返回值类型用来指定方法(行为)返回数据的类型,可以是任何类型,如果方法不需要返回值则可以使用void关键字。
- 一个成员方法(行为)可以有参数也可以没有参数,同时参数是对象也可以是基本数据类型。
class Person{
String name = "张三";//成员变量也称之为类对象属性
//定义一个方法,作用是做一个自我介绍
//不需要返回
public void showInfo(){
System.out.println(name);
}
}
public class Per{
public static void main(String[] args){
Person p = new Person();
p.showInfo();//输出张三
}
}
注意:
方法的定义必须是在某个类的里面 ,也就是在类中;同时定义方法如果没有给定权限访问修饰符,该方法的默认权限也缺少,也就是只能在本类以及同一个包中的类进行访问。
如果定义的方法有设置了返回值,则方法里必须使用return关键字返回一个指定类型的数据,并且返回类型要与方法返回值的类型一致。
2.2.2 成员方法的参数
在调用方法时可以给该方法传递一个或者多个值,传递给方法的值叫做实参,在方法内部,接受实参的变量叫作形参,形参的声明语法和变量的声明语法是一样的。在java中方法的参数主要有以下三种:
- 值参数
- 引用参数
- 不定长参数
【值参数:】
值参数是实参与形参之间按值传递,当使用值参数方法被调用时,编译器为形参分配储存空间,然后将对应的实参的值复制到形参中,由于是值类型的传递方式,所以在方法中对值类型的形参和修改不会影响实参。
例:书架上有30本书,箱子里有40本书,现吧书架上的书全部放入箱子后,使用带参数的成员方法统计箱子里书的总数。
public class Book{
public static void mian(String []){
Book b = new Book();
int num1 = 30;
int num2 = 40;
int box = b.add(num1,num2);
System.out.println("箱子书总数为:"+ box);
} //统计箱子中所有书本
public int add(int num1, int num2){
int box = 0;
box = num1+num2;
return box;
}
}
【引用参数:】
在给方法传递参数时,参数的类型数组或者其它引用类型,那么,在方法中对参数的修改会反映到原有的数组或者其他的引用类型上,这种类型的方法参数就叫做引用参数。
现将1、10、100美元存入double数组中,使用引用参数将数组的美元转化成RMB,例1:6.903
public class Rate{
public static void main(String[] args){
double[] arr = {1, 10, 100}; //输出数组中的美钞
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i] + "美元");
} //调用方法change
change(arr); //再次输出数组中数据
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i] + "元");
}
} //定义一个方法,参数为一维数组(形参)
public void change(double[] arr){
for(int i = 0; i < arr.length; i++){
arr[i] *= 6.903; //换算成RMB
}
}
}
【不定长参数:】
在声明方法的时候,如有若干个相同类型的参数,则可以定义不定长参数的成员方法。
public class Scal{
public static void main(String[] args){
int num1=20,num2=42,num3=32,num4=329,num5=329;
Scal s = new Scal();
int sum1 = s.add(num1, num2); //只计算二个数值的和
int sum2 = s.adds(num1,num2,num3,num4,num5); System.out.println("sum1=" + sum1);
System.out.println("sum2=" + sum2);
} //计算二个数之和
public int add(int num1, int num2){
return num1 + num2;
} //计算一系列整数之和
public int adds(int... num){
int sum = 0;
for(int i = 0; i < x.length; i++){
sum += x[i];
}
//返回和
return sum;
}
}
2.3 局部变量
局部变量从字面意思来理解就是在一定范围有效。
定义:成员方法内部定义的变量,那么这个变量就是局部变量。
分析:局部变量在方法执行时被创建在方法执行结束后就会被销毁。同时局部变量在使用时必须进行赋值操作或者初始化,否则会出现编译错误。
public class Demo{
public static void main(String[] args){
Demo d = new Demo();
d.sayHello();
} //说hello
public void sayHello(){
String name = "Java"; //是在方法sayHello体内声明的所以是局部变量
System.out.println(name);
} }
2.4 构造方法
2.4.1 无参构造方法定义
在类中除了有成员方法之外还有一个特殊类型的方法,那就是构造方法。构造方法是一个类与类同名的方法,我们实体就是通过构造方法来创建的。也就是说每当类实例化一个对象时,类都会自动调用构造方法。
- 构造方法没有返回值类型,也不能定义void
- 构造方法的名称要与本类的名称相同
- 构造方法主要作用是完成初始化工作,也能把定义对象的参数传给对象成员
分析:
在定义一个类的构造方法时,构造方法是没有返回值(一定要记住),同时也要知道构造方法与普通方法没有返回值的方式不同,普通方法返回值的方法用public void 方法名()形式定义,但构造方法并不需要void关键字进行修饰。
public class 类名 {
//构造方法
public 类名() { }
}
注意:
- public 修饰符关键字不能少
- 类名一定要保持一致
2.4.2 定义有参构造方法
在对构造方法中可以为成员变量进行赋值,这样当实例化一个本类的对象时,相应的成员变量也会被初始化。类中没有定义构造方法时,编译器会自动创建一个不带参数的构造方法作为默认。
public class Book {
//书名
String name;
//定义一个有参数的构造方法
public Book(String str){
name = str;
}
}
注意:
- public修饰符关键字不能少
- 类名一定要保持一致
- 构造方法的参数可以是一个或多个
分析:
如果在类中定义的构造方法是有参构造方法,编译器就不会为类自动生成一个默认无参构造方法,此时当调用无参构造方法实例化一个对象时,编译器就会报错。因此要记住,只有在类中没有定义构造方法时,编译器才会去自动生成一个不带参数的构造方法。
public class Per{
public static void main(String[] args){
Per p = new Per();
p.sayHello("张三", "男");
}
//无参构造方法
public Per(){
}
//介绍自己
public void sayHello(String name, String sex){
System.out.println("我的名字"+ name + ",性别是" + sex);
}
}
public class Per{
String username; //成员变量
String agender; //成员变量
public static void main(String[] args){ }
//有参构造方法
public Per(String name, String sex){
username = name;
agender = sex;
}
public void sayHello(){
System.out.println("我的名字是:" + username + ",性别为:" + agender);
}
}
2.5 this关键字
this关键字在方法体内表示当前类的对象。类是对象的载体,把通过类可以创建出很多的对象,那么当创建的对象去调用方法时,被调用的方法体内有this关键字,那么这个方法体内的this就是当前对象自己本身。
关于this的三种用法:
1.区分成员变量和局部变量
public class Demo{
public static void main(String[] args){
Demo2 d = new Demo2("张三", 32);
d.sayHello();
}
}
class Demo2{
String name; //名字
int age; //年龄
public Demo2(String name, int age){
name = name;
age = age;
} //说出自己个人信息
public void sayHello(){
System.out.println("我的名字是" + name + ",年龄为" + age);
}
}
输出结果为:我的名字是null,年龄为0
在我们构造方法中如果没有使用this来作为变量区分,那么name = name 和 age = age 都是局部变量在操作。也就是局部变量name = 局部变量name,所以成员变量name就一直没有操作。
public class Demo{
public static void main(String[] args){
Demo2 d = new Demo2("张三", 32);
d.sayHello();
}
}
class Demo2{
String name; //名字
int age; //年龄
public Demo2(String name, int age){
this.name = name;
this.age = age;
} //说出自己个人信息
public void sayHello(){
System.out.println("我的名字是" + name + ",年龄为" + age);
}
}
输出结果为:我的名字是张三,年龄为32
总结:this在构造方法中,如果参数名称和成员变量一样,则可以使用this来进行区分。
2.构造方法中的使用
public class People{
String name; //姓名
int age; //年龄
String agender; //性别
public static void main(String[] args){
People p = new People("张三");
p.sayHello();
}
public People(String name, String agender, int age){
this.name = name;
this.agender = agender;
this.age = age;
System.out.println("这是类的第一个构造方法");
}
public People(String name, String agender){
this.name = name;
this.agender = agender;
System.out.println("这是类的第二个构造方法");
}
public People(String name){
this.name = name;
System.out.println("这是类的第三个构造方法");
}
public void sayHello(){
System.out.println("name=" + name + ",agender=" + agender + ",age=" +age);
}
}
输出结果为:
这是类的第三个构造方法
name=张三,agender=null,age=0
如果在类构造方法中使用this关键字后:
public class People{
String name; //姓名
int age; //年龄
String agender; //性别
public static void main(String[] args){
People p = new People("张三");
p.sayHello();
}
public People(String name, String agender, int age){
this.name = name;
this.agender = agender;
this.age = age;
System.out.println("这是类的第一个构造方法");
}
public People(String name, String agender){
this(name, agender, 32);
this.name = name;
this.agender = agender;
System.out.println("这是类的第二个构造方法");
}
public People(String name){
this(name, "男");
this.name = name;
System.out.println("这是类的第三个构造方法");
}
public void sayHello(){
System.out.println("name=" + name + ",agender=" + agender + ",age=" +age);
}
}
输出结果为:
这是类的第一个构造方法
这是类的第二个构造方法
这是类的第三个构造方法
name=张三,agender=男,age=32
3.表示当前对象
public class Demo{
String name;
int age;
public static void main(String[] args){
Demo d = new Demo("张三", 32);
System.out.println(d.name + d.age);
} public Demo(String name, int age){
this.name = name;
this.age = age;
}
}
分析:
this表示当前调用对象也就是对象“d”,那么构造方法中的this.name就完全等价于d.name = “张三”。
3 static关键字
在代码中使用static关键字修饰的变量、方法、常量都被称为静态变量、方法、常量,也可以称之为类的静态成员。
静态成员的使用不需要实例化对象就可以使用,使用的方法也很简单就是【类名.家庭成员】
3.1 静态成员
public class StaticStu
{
public static String name = "";
public static void main(String[] args){
name = "张三"; //等价于StaticStu.name = "张三"
System.out.println(name);
}
}
//输出的结果为:张三
注意:
在类中使用静态成员可以直接使用,也是不需要实例化。
3.2静态方法
public class StaticStu
{
public static void main(String[] args){
StaticStu.SayHello();
} public static void SayHello(){
System.out.println("深夜了");
}
}
//输出结果为:深夜了
注意:
定义和使用跟变量一样,都是static进行修饰,也不需要实例化就可直接使用
3.3 静态代码块
类有类的成员,那么类也有着自己的行为,那就是类的代码块,也称之为静态代码块。主要作用和构造方法雷同,是用来为为类做一些初始化工作。
public class StaticStu
{
static {
System.out.println("我是类的代码块,我初始化了");
}
public static void main(String[] args){
}
}
//输出结果为:我是类的代码块,我初始化了
注意:
类有代码块那么对象也有代码块,直接是以{}即可。