文章目录
面向对象编程(OOP)
Object Oriented Programming
对象 : Object
C 面向过程
C++ 半面向过程半面向对象
Java 面向对象: 把大象装进冰箱.
介绍
什么是类
具有相同特点(属性)和行为(动作)的集合的总称.
人类
植物类
属性和行为
什么是对象
是某一类的具体体现 实例
将类的抽象概念具体化.
人类的对象: 张三,特朗普,…
植物类的对象 : 路边的梧桐,杨树
手机类的对象 : 正在使用的手机
什么是属性
是一类事物的特点/特征.
人类的属性/特征 : 肤色,年龄,身高,体重…
植物类的属性 : 树干,树叶,树根,花,果实
手机的属性 : 价格,重量,颜色,形状
什么是方法
一类事物都可以进行的动作/行为.
人类的动作 : 吃饭睡觉打豆豆
植物的动作 : 开花,结果,光合作用
手机的动作 : 打电话,发短信
方法
什么是方法?
方法:在程序中要去实现的某一个功能,需要包含多条语句,这些语句包含循环语句结构,选择语句结构等共同来处理一件事情.
定义方法的格式详解
public static void main(String[] args){
//执行语句
System.out.println();
}
* [访问修饰符] 返回值类型 方法名([参数1],[参数2],...){
* 方法内的执行语句;
* ...
* }
* 访问修饰符 : 控制访问权限
* 返回值类型 : 该方法执行后返回的结果的数据类型
* 基本数据类型/引用数据类型
* void : 空,方法执行后不返回任何数据
* ---
* 如果方法需要返回数据,
* 1) 那就需要在返回值类型处写上返回数据的数据类型
* 2) 在方法体的最后使用 return 值;的格式将值明确显示返回.
* 3)只要不是void,必须在方法后加: return 值;
* 4)return 后只能有一值;
* 5)如果需要返回多个值需要将多个值放进数组或方法,将数组或方法返回
* eg.public static void main(String[] args){
* int[] arr = returnMoreValue(1,2);
* System.out.println(arr[0]);
* System.out.println(arr[1]);
* }
* //方法执行返回多个值:2个值为例
* //需要将多个值放入数组,将数组返回
* public static int[] returnMoreValue(int a,int b){
* int[] arr = new int[2];
* arr[0] = a;
* arr[1] = b;
* return arr;
* }
* 方法名 : 见名知意,驼峰原则
* () 参数列表 :
* 1 形式参数 : 该方法执行可能用到的数据
* 2 形式参数的写法: 数据类型 变量名;
* 3 列表内可以写多个参数,多个参数之间用逗号隔开,或者可以不写
* 4 当方法参数列表有参数时,在调用时(让方法执行时)
* 就必须给方法的参数赋值
* 参数类型:进入方法当中的数据是一个什么样的类型
* 参数名称:进入方法当中的数据对应的变量名称
* {
} 方法体
* 备注:方法不允许嵌套
* 执行语句 : 该方法真正的功能体现
Java中方法的分类
JAVA中方法的分类
构造方法
- 构造方法:类或者抽象类中(接口没有),与类名同名,无返回值,不能用static修饰。
- 格式:权限修饰符 类名(参数){方法体}
- 作用:初始化实例对象。
- 调用:创建类的实例对象时,自动调用。
- 继承性:无参构造其子类会自动调用父类的无斜体样式参构造supper()。含参构造不会被继承。
注意:构造方法分为含参构造和无参构造。JAVA会在编译时自动生成无参构造,但若书写了含参构造,则必须自己写无参构造,否则只能调用含参构造。
静态方法
- 定义:类/接口中,用static修饰的方法。
- 格式: 权限修饰符 static 返回值类型 方法名(参数){} (static可与final,private共存)
- 特点:
- 静态方法属于整个类,不单独属于类的某一个对象。
- 静态方法类加载便存在,比对象先存在,随类而消亡。
实例/默认方法
抽象方法
私有方法
数组作为方法参数和返回值
数组作为方法参数
数组作为应用类型能够当成方法的参数进行传递呢?当然可以
- 数组作为方法参数传递,传递的参数是数组内存的地址
public static void main(String[] args){
int[] arr = {
1,2,3,4,5};
//调用方法,传递数组
println(arr);
}
public static void println(int[] arr){
for (int i = 0; i < arr.length - 1; i++) {
System.out.println(arr[i]);
}
}
对象的创建及使用
* 通过类 创建对象 <==> 实例化
* 类名 对象名 = new 类名();
* -----------------------
* 数据类型 变量名 = 值;
* -----------------------
* 对象属性取值:
* 数据类型 变量名 = 对象名.属性名;
*
* 对象属性赋值:
* 对象名.属性名 = 值;
*
* 调用对象的方法[重点]
* 三种调用格式:
* 1.单独调用:对象名.方法名(参数具体值);
* 2.打印调用:System.out.println(对象名.方法名(参数具体值));
* 3.赋值调用:数据类型 变量名 = 对象名.方法名(参数具体值);
* 备注:当返回值类型为void的时候,这种方法只能单独调用,不能进行打印调用或者赋值调用
* 返回值类型一般可以理解为数据类型(基本数据类型和引用数据类型),此外还包含一种类型void类型,当方法执行完毕不需要给程序调用者返回人和的数据结果时,可以指定该方法的返回值类型为void,此时只能[单独调用]
* 1) 方法有参数,调用时必须传入实参
* 实参与形参的个数,顺序,数据类型要保持
* 2) 方法没有参数,不能给参数
* 3) 方法无返回值,一定不能接收返回值
* 4) 方法有返回值,可以接收,也可以不接收
* A : 无返回值
* A1 无返回值无参
* 对象名.方法名();
* A2 无返回值有参数
* 对象名.方法名(值1,值2,..);
* B : 有返回值
* B1 有返回值无参
* [数据类型 变量名 = ]对象名.方法名();
* B2 有返回值有参数
* [数据类型 变量名 = ]对象名.方法名(值1,值2,..);
public static void main(String[] args){
// 创建对象
Student stu1 = new Student();
System.out.println(stu1);
// 获得属性值
String name = stu1.name;
int age = stu1.age;
String stuNo = stu1.stuNo;
String schoolName = stu1.schoolName;
System.out.println("name = "+name);
System.out.println("age = "+age);
System.out.println("stuNo = "+stuNo);
System.out.println("schoolName = "+schoolName);
// 属性赋值
stu1.name = "张三";
stu1.age = 18;
stu1.schoolName = "北京大学";
stu1.stuNo = "100001";
System.out.println("name = "+stu1.name);
System.out.println("age = "+stu1.age);
System.out.println("stuNo = "+stu1.stuNo);
System.out.println("schoolName = "+stu1.schoolName);
System.out.println("----------分割线---------");
// A1 无返回值无参
stu1.eat();
// A2 无返回值有参数
stu1.sleep("地");
// B1 有返回值无参
String result1 = stu1.playGame();
System.out.println("结果 : "+result1);
// B2 有返回值有参数
String result2 = stu1.study("<java从入门到精通>", "黑笔");
System.out.println("谁在学习 ? : " + result2);
}
public class Student{
/*
* 属性的写法:
* [访问修饰符] 数据类型 变量名;
* []内的代码,可写可不写
*/
public String name;
public int age;
public String stuNo;
String schoolName;
public String study(String book,String pen) {
System.out.println("在学习"+book);
String name = "张三";
// return "李四";
return name;
}
void eat() {
System.out.println("吃");
}
void sleep () {
System.out.println("睡觉");
}
}
方法的重载和方法的重写
重载(Overload)
1.在同类中,方法名一样,参数列表不一样的方法之间叫做重载.
2.方法重载与那些因素有关:
- 参数的个数不同
- 参数的类型不同
- 参数的多类型顺序不同
3.方法重载与那些因素无关:
- 与参数的名称无关
- 与方法的返回值类型无关
- 与方法的修饰符无关
好处:只需要记住唯一一个方法名称即可,就可以实现类似的多个功能.
重写(Override)
定义:重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变.
重写的规则:
- 参数列表必须完全与被重写方法相同
- 返回值必须完全相同
- 访问权限不能比父类中被重写的方法的访问权限更低
- 父类私有(private)方法不能被重写
- 声明为final的方法不能被重写
- 声明为static的方法不能被重写,但能被再次声明
- 如果子类不是抽象类,子类必须重写父类中的abstract的方法
- 如果子类和父类在同一个包下,子类可以被重写除private和final之外的所有方法
- 如果子类和父类不在同一个包下,子类能重写父类中被public修饰和protected修饰的方法
- 重写方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常.但是,重写的方法不能抛出新的强制性异常
注:所谓强制性异常,就是在编写程序的过程中,必须在抛出异常的部分try-catch或者向上throw异常
三大基本特征
继承 封装 多态
继承
1.场景:
如果多个类存在相同的属性和行为时,将这些内容抽取到单独一个类中,
那么多个类无需再定义这些属性和行为,只要继承那一个类即可。
其中,多个类可以称为子类,单独的那个类称为父类、超类、基类
继承描述的是事物之间的所属关系,这种关系是:is-a的关系。
父类更通用,子类更具体。我们主要是通过继承,可以使事物之间形成一种关系体系。
2.定义:
就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。
子类可以直接访问父类中的非私有的属性和行为。
3.好处:
1)提高代码的复用性
2)使得类与类之间产生了关系,是多态的前提。
4.继承格式:
通过关键字extends,可以声明一个子类继承另一个父类
class SuperClass{
…
}
class Subclass extends SuperClass{
…
}
-
继承后的特点—成员变量
1.成员变量不重名
如果子类父类中出现不重名的成员变量,这时访问时没有影响的。
如果重名,这时访问是受影响的。
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量,就需要使用super关键字,
修饰父类成员变量,类似于关键字this
2.使用格式:
super.父类成员变量名;
备注:父类中的成员变量是非私有的,子类才可以直接访问。若父类中的成员变量私有了,子类不能直接访问的。
通常编码时,我们一般遵循封装的原则,可以在父类中提供公共的setXxx()和getXxx()方法。 -
继承后的特点—成员方法
1.成员方法不重名
如果子类父类中出现不重名的成员方法时,这时的调用没有任何的影响。
对象调用方法时,会先在子类中查找有没有对应的方法,若子类存在就会执行子类中的成员方法,
若不存在就会执行父类中相应的方法。
2.成员方法重名—重写(Override)
方法重写:子类出现于父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效应
也称为重写或者复写。声明不变,重新实现。
3.重写的应用
子类可以根据需要,定义特定于自己的行为,即沿袭了父类的功能名称,又能根据子类的需要重新实现父类
的方法,从而进行扩展增强。比如:新的手机来电显示功能。
备注:
1.子类方法重写覆盖父类方法时,必须保证权限大于等于父类的权限。
2.子类方法重写父类方法时,返回值类型,方法名和参数列表必须一模一样。
在没有使用@Override时,子类定义父类方法时,方法名和参数列表可变,返回值类型不可变。- 继承的特点:
1.java只支持单继承,不支持多继承。
2.java支持多层继承(继承体系)
3.子类和父类是一种相对概念。
备注:顶层父类是Object类,所有的类默认都继承Object类。
- 继承的特点:
封装
1.封装:就是隐藏对象的属性和实现细节,仅对外提供公共访问方式,封装使用get,set方法。
2.封装的好处:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息,实现细节。
3.封装时的权限控制符区别如下:
假如:有一个学生类Student
public class Student{
public int age;
public string name;
public Date date;
}
外部使用Student时,
public static void main(String[] args){
Student stu = new Student();
stu.age=16;
stu.name="john";
stu.date=2017;
}
但是,现实中如果很多外部代码都使用了Student这个类;某一天,如果这个类的age需要换成String类型,那么,外部使用它的任何地方都需要需改xxx.age=“xxx”,这将是非常繁琐的一个过程。
但是如果使用封装属性,开放访问接口的方法:
public class Student{
private String age; //修改int to String
private string name;
public void setAge(String age){
this.age = String.valueOf(age); //修改
}
public String getAge(){
return this.age;
}
}
这样外部使用它的地方都不用修改,只用修改对象内部就可以了,更加方便快捷。到了这里我们确实可以看出,封装确实可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码。
多态(polymorphic)
Java中:同一个方法,传入相同类型的参数,但是运行结果不一样.
Java多态:让程序在运行时自行决定执行哪些方法
多态的三种表现形式
1.普通类多态定义的格式
父类 变量名 = new 子类();
2.抽象类多态定义格式
3.接口多态定义格式
多态的前提
1.子父类关系
2.子类必须重写父类方法
3.父类引用指向子类对象
父类型 变量 = 子类对象;==>向上转型
属性没有多态性,方法有多态性
编译看父类,运行看子类
多态有什么好处?
有两个好处:
A:提高了代码的维护性(继承保证)
B:提高了代码的扩展性(由多态保证)
猫狗案例代码
class Animal {
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}
}
class Dog extends Animal {
public void eat(){
System.out.println("狗吃肉");
}
public void sleep(){
System.out.println("狗站着睡觉");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void sleep() {
System.out.println("猫趴着睡觉");
}
}
class Pig extends Animal {
public void eat() {
System.out.println("猪吃白菜");
}
public void sleep() {
System.out.println("猪侧着睡");
}
}
//针对动物操作的工具类
class AnimalTool {
private AnimalTool(){
}
/*
//调用猫的功能
public static void useCat(Cat c) {
c.eat();
c.sleep();
}
//调用狗的功能
public static void useDog(Dog d) {
d.eat();
d.sleep();
}
//调用猪的功能
public static void usePig(Pig p) {
p.eat();
p.sleep();
}
*/
public static void useAnimal(Animal a) {
a.eat();
a.sleep();
}
//把所有的可能都归为动物类
}
class DuoTaiDemo2 {
public static void main(String[] args) {
//我喜欢猫,就养了一只
Cat c = new Cat();
c.eat();
c.sleep();
//我很喜欢猫,所以,又养了一只
Cat c2 = new Cat();
c2.eat();
c2.sleep();
//我特别喜欢猫,又养了一只
Cat c3 = new Cat();
c3.eat();
c3.sleep();
//...
System.out.println("--------------");
//问题来了,我养了很多只猫,每次创建对象是可以接受的
//但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。
//我们准备用方法改进
//调用方式改进版本
//useCat(c);
//useCat(c2);
//useCat(c3);
//AnimalTool.useCat(c);
//AnimalTool.useCat(c2);
//AnimalTool.useCat(c3);
AnimalTool.useAnimal(c);
AnimalTool.useAnimal(c2);
AnimalTool.useAnimal(c3);
System.out.println("--------------");
//我喜欢狗
Dog d = new Dog();
Dog d2 = new Dog();
Dog d3 = new Dog();
//AnimalTool.useDog(d);
//AnimalTool.useDog(d2);
//AnimalTool.useDog(d3);
AnimalTool.useAnimal(d);
AnimalTool.useAnimal(d2);
AnimalTool.useAnimal(d3);
System.out.println("--------------");
//我喜欢宠物猪
//定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用
Pig p = new Pig();
Pig p2 = new Pig();
Pig p3 = new Pig();
//AnimalTool.usePig(p);
//AnimalTool.usePig(p2);
//AnimalTool.usePig(p3);
AnimalTool.useAnimal(p);
AnimalTool.useAnimal(p2);
AnimalTool.useAnimal(p3);
System.out.println("--------------");
//我喜欢宠物狼,老虎,豹子...
//定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用
//前面几个必须写,我是没有意见的
//但是,工具类每次都改,麻烦不
//我就想,你能不能不改了
//太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢?
//改用另一种解决方案。
}
/*
//调用猫的功能
public static void useCat(Cat c) {
c.eat();
c.sleep();
}
//调用狗的功能
public static void useDog(Dog d) {
d.eat();
d.sleep();
}
*/
}
多态的弊端:
不能使用子类的特有功能。
怎么才能使用子类特有的功能?
A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
B:把父类的引用强制转换为子类的引用。(向下转型)
注:向下转型中有可能的异常:
ClassCastException:类型转换异常一般在多态的向下转型中容易出现