目录
面向对象编程
前言
首先声明,本人大一菜鸟,是一个刚入IT界末流小白,我用王者荣耀来说面向对象,作为学习笔记,仅用于巩固知识。
我想此篇对大家会有帮助的,如果有错误的地方还请大佬指出,
谢谢!!
1.java面向对象概述
在用王者来说面向对象之前还是先来看一下面向对象基本结构吧!!!
1.1类与对象
类是一个模板,对象是一个具体的实例。
1.1.1类:类是描述一组具有相同特征(属性)和行为(方法)的一组对象的集合。王者中所有的英雄构成的一个集合就可以看成一个类(英雄池)。
类的定义:
权限修饰符 class 类名{
代码块
}
public class YingXong {
public String name;//英雄名字
public String zhiYe;//英雄的职业类型
public String dingWei;
public String teChang;
public int xueLiang;
public int yiSu;
}
//定义一个刺客类
class CiKe extends YingXong {
public String name;
public String teChang;
public int xueLiang;
public int yiSu;
}
1.1.2对象:王者中的每一个英雄都可以说是一个具体的对象(他们都有自己的名字、属性和技能,一说出他你就能知道是谁。)所以呢对象就是一个明确的东西,你可以很了解她。
下面用一个结构来说明类与对象
所有英雄是一大的类,英雄下面分别又分为:刺客、射手、法师、战士、坦克和辅助六类。你们常玩的每个英雄就是一个对象,例如:李白、韩信、澜等等都是一个对象。
- 创建对象:
- 声明:对象类型(类名) 对象名;
CiKe liBai;
- 实例化:使用new关键字;
liBai = new CiKe();
- 也可以在声明时就实例化:
CiKe liBai = new CiKe()
YingXong hanxin = new Yingxong();
- 初始化:使用new关键字创建对象时,会调用构造方法初始化对象
- 对象的应用
引用类型:基本类型(8)
对象是通过引用来操作的:栈---->堆
- 属性:字段field 成员变量
默认初始化:
数字 0 0.0
char: \u000
Boolean :false
引用:null
修饰符 属性类型 属性名 = 属性值
- 对象的创建与使用
- 必须使用new关键字创建对象,构造器
- 对象属性
- 对象方法
1.2方法
1.2.1方法定义:
修饰符 返回类型 方法名(参数列表){
方法体
return 方法 返回值;
}
若没有返回值,返回值类型为void,并省略return。
public class YingXong{
public void jiNeng1(String name){
System.out.println("技能1:"+name);
}
public void jiNeng2(String name){
System.out.println("技能2:"+name);
}
public void jiNeng3(String name){
System.out.println("技能3:"+name);
}
public int xueLiang(int xueLiang){
return xueLiang;
}
}
传参时参数类型、个数、顺序均需一致.上面是不可变参数,下面来说说不可变参数!
可变参数用类型...
定义,相当于数组类型。可变参数的参数类型必须一致并且必须放在参数列表的最后一个。
修饰符 返回值类型 方法名(参数类型... 参数名)
this.参数名 = 参数名;
可变参数也可以用数组来定义
修饰符 返回值类型 方法名(参数类型[]参数名)
this.参数名 = 参数名;
1.2.2方法的调用
类名.方法名(参数)
(静态方法才可以这样调用)
对象.方法名(参数)
public class CeShi {
public static void main(String[] args) {
CiKe hanxin;
hanixn =new CiKe();
CiKe.pirntXueLiang();//类名.方法名调用
hanixn.jiNeng1("无情冲锋");//对象.方法名调用
}
}
classI CiKe {
public static int xueLiang = 4500;
static void pirntXueLiang(){
System.out.println("血量:"+xueLiang);
}
public void jiNeng1(String name){
System.out.println("技能1:"+name);
}
}
/*//运行结果:
血量:4500
技能1:无情冲锋
*/
1.2.3构造方法:用于初始化一个新的对象(构造方法又称构造器)
- 什么是构造方法:与类名相同的方法就是构造方法。
- 构造方法参数没有限制在方法内可以编写任意语句。
- 构造方法没有返回值(也没有void)所以也不能用return开返回当前 类的对象,调用构造方法必须用new关键字操作。
- 类中没有定义构造方法时编译器会自动创建一个无参的构造方法。
- 构造方法可以定义多个。
- 在一个构造方法内部可以调用另一个构造方法,普通方法不能调用构造方法。
注:1、构造方法不能被static、final、abstract、synchronized、和native修饰。因为构造方法不能被子类继承,所以final和abstract修饰无意义;多线程不会创建内存地址相同的一个对象,所以synchronized修饰也没比要。
2、构造方法 是对象一建立就运行,给对象初始化,就包括属性,执行方法中的语句;而一般方法被调用时才执行。
而一般函数是对象调用才执行,用 .方法名
的方式,给对象添加功能。
3、一个对象建立,构造方法只执行一次;而一般方法可以该对象调用 多次。
4、子类所有的 构造函数 默认调用父类的无参构造函数(构造函数不会被继承,只是被子类调用而已),父类参数是private的,无法直接访问,需要在父类中使用get方法来调用私有变量值。
public class YingXong{
public void jiNeng1(String name){
System.out.println("技能1:"+name);
}
YingXong(){
System.out.println("我是一个无参构造器");
}
YingXong(String name){
System.out.println("我是一个有参构造器 "+name);
}
}
//定义测试
class CeShi {
public static void main(String[] args) {
YingXong liBai = new YingXong();//创建对象时自动调用了无参构造器
liBai.jiNeng1("将进酒");
CiKe hanXin = new CiKe(); //创建子对象时自动调用了父类的无参构造器
}
}
1.2.4方法重载(overlord)
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
public class YingXong {
public void jiNeng(String name){
System.out.println("技能1:"+ name);
}
public void jiNeng(String name,String name2){
System.out.println("技能1:"+ name+"技能2:"+ name2);
}
public void jiNeng(String name, String name2,String name3){
System.out.println("技能1:"+ name+"技能2:"+ name2+"技能3:"+ name3);
}
}
public class CeShi {
public static void main(String[] args) {
YingXong liBai = new YingXong();
liBai.jiNeng("将进酒","神来之笔","青莲剑歌");
liBai.jiNeng("将进酒","神来之笔");
liBai.jiNeng("将进酒");
/*运行结果
技能1:将进酒技能2:神来之笔技能3:青莲剑歌
技能1:将进酒技能2:神来之笔
技能1:将进酒
*/
2.封装
修饰符的可访问性:
封装将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。
记住:属性私有 , get/set方法
封装的特点:
- 只能通过规定的方法访问数据(get/set)。
- 隐藏类的实例细节,方便修改和实现。
实现封装的具体步骤如下:
- 修改属性的可见性来限制对属性的访问,一般设为 private。
- 为每个属性创建一对赋值(setter)方法和取值(getter)方法,一般设为 public,用于属性的读写。
- 在赋值和取值方法中,加入属性控制语句(对属性值的合法性进行判断)。
public class CeShi {
public static void main(String[] args) {
YingXong liBai = new YingXong();
liBai.setName("李白");
liBai.setDingWei("刺客");
System.out.println(liBai.getName());
System.out.println(liBai.getDingWei());
public class YingXong {
private String name;//英雄名字
public String zhiYe;//英雄的职业类型
private String dingWei;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDingWei() {
return dingWei;
}
public void setDingWei(String dingWei) {
this.dingWei = dingWei;
}
3.继承(extends)
继承就是在已经存在类的基础上进行扩展,从而产生新的类。已经存在的类称为父类、基类或超类,而新产生的类称为子类或派生类。在子类中,不仅包含父类的属性和方法,还可以增加新的属性和方法。
子类是父类的扩展
public class YingXong {
private String name;//英雄名字
public String zhiYe;//英雄的职业类型
private String dingWei;
public int xueLiang(int xueLiang){
return xueLiang;
}
public void jiNeng1(String name){
System.out.println("技能1:"+name);
}
public void jiNeng2(String name){
System.out.println("技能2:"+name);
}
public void jiNeng3(String name){
System.out.println("技能3:"+name);
}
}
//定义一个刺客类
public class CiKe extends YingXong{
public static int xueLiang;
static void pirntXueLiang(){
System.out.println("血量:"+xueLiang);
}
public CiKe() {
}
}
//子类可以拥有父类的非private修饰的属性和方法,并且可以添加新的属性和方法。
注意:如果在父类中存在有参的构造方法而并没有无参的构造方法,那么在子类中必须含有有参的构造方法,因为如果在子类中不含有构造方法,默认会调用父类中无参的构造方法,而在父类中并没有无参的构造方法,因此会出错。
Java 不支持多继承,只允许一个类直接继承另一个类,即子类只能有一个直接父类,extends 关键字后面只能有一个类名.但可以有多个间接父类。
父类中的 private 成员在子类中是不可见的,因此在子类中不能直接使用它们。
方法重写(override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。
例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。
方法重写的规则:
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同;返回值类型必须<=父类的返回值类型)。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 子类和父类在同一个包中时,子类可以重写父类的所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中时,子类只能重写父类的声明为 public 和 protected 的非 final 方法。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
//定义一个刺客类
public class CiKe extends YingXong{
public String teChang;
public static int xueLiang;
public int yiSu;
//定义方法(技能)
public void jiNeng1(String name){
System.out.println(name+"是技能1");
}
public void jiNeng2(String name){
System.out.println(name+"是技能2");
}
public void jiNeng3(String name){
System.out.println(name+"是技能3");
}
}//Yingxong类在上面
4.多态(方法的多态)
同一变量、同一方法执行出的结果不同。
**对面向对象来说,多态分为编译时多态和运行时多态。**其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。
实现多态有 3 个必要条件:继承、重写和向上转型。
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。
类型转换
public class CeShi {
public static void main(String[] args) {
YingXong lan = new CiKe();//向上转型
lan.jiNeng1("破浪");
CiKe lan1 = (CiKe)lan;//向下转型
lan1.jiNeng1("polang");
lan1.jiNeng("破浪");
((CiKe) lan).pirntXueLiang();
}
}
class YingXong {
public void jiNeng(String name){
System.out.println("技能1:"+ name);
}
public int xueLiang(int xueLiang){
return xueLiang;
}
public void jiNeng1(String name){
System.out.println("技能1:"+name);
}
}
class CiKe extends YingXong{
public int xueLiang = 4320;
public void jiNeng1(String name){
System.out.println(name+"是技能1");
}
public void pirntXueLiang(){
System.out.println("血量:"+xueLiang);
}
}
/*运行结果
破浪是技能1
polang是技能1
技能1:破浪
血量:4320
*/
向上转型后该对象只能调用父类的方法,如果该方法被子类重写,则实现子类重写的方法;不能调直接用子类独有的方法 必须先向下转型((CiKe) lan).pirntXueLiang();
。
向下转型后该对象可以调用父类及本类所有方法,除被private修饰的方法。
5.关键字
this
this 关键字可用于任何实例方法内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。
this.属性名:
大部分时候,普通方法访问其他方法、成员变量时无须使用 this 前缀,但如果方法里有个局部变量和成员变量同名,但程序又需要在该方法里访问这个被覆盖的成员变量,则必须使用 this 前缀。
提示:当一个类的属性(成员变量)名与访问该属性的方法参数名相同时,则需要使用 this 关键字来访问类中的属性,以区分类的属性和方法中的参数。
this.方法名(参数):调用当前对象的方法
this():调用本类的构造器
super
由于子类不能继承父类的构造方法,因此,如果要调用父类的构造方法,可以使用 super 关键字。super 可以用来访问父类的构造方法、普通方法和属性。
当需要在子类中调用父类的被重写方法时,要使用 super 关键字。
功能:
- 在子类的构造方法中显式的调用父类构造方法
- 访问父类的成员方法和变量。
- super 关键字可以在子类的构造方法中显式地调用父类的构造方法,
- 当子类的成员变量或方法与父类同名时,可以使用 super 关键字来访问。
- 当父类和子类都具有相同的方法名时,可以使用 super 关键字访问父类的方法。
super和this的区别
this 指的是当前对象的引用,super 是当前对象的父对象的引用。
super 关键字的用法:
- super.父类属性名:调用父类中的属性
- super.父类方法名:调用父类中的方法
- super():调用父类的无参构造方法
- super(参数):调用父类的有参构造方法
如果构造方法的第一行代码不是 this() 和 super(),则系统会默认添加 super()。
this 关键字的用法:
- this.属性名:表示当前对象的属性
- this.方法名(参数):表示调用当前对象的方法
当局部变量和成员变量发生冲突时,使用this.
进行区分。
关于super 和 this 关键字的异同,可简单总结为以下几条。
- 子类和父类中变量或方法名称相同时,用 super 关键字来访问。可以理解为 super 是指向自己父类对象的一个指针。在子类中调用父类的构造方法。
- this 是自身的一个对象,代表对象本身,可以理解为 this 是指向对象本身的一个指针。在同一个类中调用其它方法。
- this 和 super 不能同时出现在一个构造方法里面,因为 this 必然会调用其它的构造方法,其它的构造方法中肯定会有 super 语句的存在,所以在同一个构造方法里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this( ) 和 super( ) 都指的是对象,所以,均不可以在 static 环境中使用,包括 static 变量、static 方法和 static 语句块。
- 从本质上讲,this 是一个指向对象本身的指针, 然而 super 是一个 Java 关键字。
final
final 修饰的变量即成为常量,只能赋值一次,但是 final 所修饰局部变量和成员变量有所不同。使用 final 声明变量时,要求全部的字母大写
- final 修饰的局部变量必须使用之前被赋值一次才能使用。
- final 修饰的成员变量在声明时没有赋值的叫“空白 final 变量”。空白 final 变量必须在构造方法或静态代码块中初始化。
当使用 final 修饰基本类型变量时,不能对基本类型变量重新赋值,即final修饰的变量只能被赋值一次。
final 修饰的方法不可被重写,如果出于某些原因,不希望子类重写父类的某个方法,则可以使用 final 修饰该方法。
final 修饰的类不能被继承。当子类继承父类时,将可以访问到父类内部数据,并可通过重写父类方法来改变父类方法的实现细节,这可能导致一些不安全的因素。为了保证某个类不可被继承,则可以使用 final 修饰这个类。
instanceof
instanceof 关键字判断一个对象是否为一个类(或接口、抽象类、父类)的实例,语法格式如下所示。
boolean result = obj instanceof Class
其中,obj 是一个对象,Class 表示一个类或接口。obj 是 class 类(或接口)的实例或者子类实例时,结果 result 返回 true,否则返回 false。
public class CeShi {
public static void main(String[] args) {
CiKe hanXin;
hanXin = new CiKe();
System.out.println(hanXin instanceof YingXong);//前者必须是引用类型即对象名
}
}
public class CiKe extends YingXong{
}//运行结果:true
static
在类中,使用 static 修饰符修饰的属性(成员变量)称为静态变量,也可以称为类变量,常量称为静态变量,修饰的方法称为静态方法或类方法,修饰的代码块表示静态代码块,它们统称为静态成员,归整个类所有即静态成员是被多个实例所共享的。。
注意:
- static 修饰的成员变量和方法,从属于类。
- 普通变量和方法从属于对象。
- 静态方法不能访问非静态成员。
- 不能修饰普通类,但可以修饰内部类。
1.静态变量与实例变量
静态变量:
- 运行时,Java 虚拟机只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配。
- 在类的内部,可以在任何方法内直接访问静态变量。
- 在其他类中,可以通过类名访问该类中的静态变量。
实例变量:
- 每创建一个实例,Java 虚拟机就会为实例变量分配一次内存。
- 在类的内部,可以在非静态方法中直接访问实例变量。
- 在本类的静态方法或其他类中则需要通过类的实例对象进行访问。
2.静态方法与实例方法:
- 静态方法不需要通过它所属的类的任何实例就可以被调用,因此在静态方法中不能使用 this 关键字,也不能直接访问所属类的实例变量和实例方法,但是可以直接访问所属类的静态变量和静态方法。另外,和 this 关键字一样,super 关键字也与类的特定实例相关,所以在静态方法中也不能使用 super 关键字。
- 在实例方法中可以直接访问所属类的静态变量、静态方法、实例变量和实例方法。
3.静态代码块:
静态代码块指 Java 类中的 static{ } 代码块,主要用于初始化类,为类的静态变量赋初始值,提升程序性能。
静态代码块的特点:
- 静态代码块类似于一个方法,但它不可以存在于任何方法体中。
- 静态代码块可以置于类中的任何地方,类中可以有多个静态初始化块。
- Java 虚拟机在加载类时执行静态代码块,所以很多时候会将一些只需要进行一次的初始化操作都放在 static 代码块中进行。
- 如果类中包含多个静态代码块,则 Java 虚拟机将按它们在类中出现的顺序依次执行它们,每个静态代码块只会被执行一次。
- 静态代码块与静态方法一样,不能直接访问类的实例变量和实例方法,而需要通过类的实例对象来访问。
4.静态带导入
在用import导入包或者类时,可以用static修饰包名或者类,表示静态导入。静态导入可以与动态导入放在一起比较来加深理解。
动态导入是当你程序运行时需要new一个不在此包中的类的对象时,才会根据全路径类名加载类;而静态导入则是随着类的加载而加载静态导入的类,所以它是提前导入的。
静态导入常用于静态方法以及含有静态方法的类,枚举类等的导入,可以在编译阶段确定导入类的信息或者方法信息。