面向对象笔记
面向对象
对象:一组有关信息(数据),表示一个事物。代表软件中的一个事物个体。
eg:"Tom, 5 ,男 ,100.0"代表了个员工个体。
类:用于定义对象的数据结构,约定对象的内容。
eg:一个员工包括4个数据
分别是姓名,年龄,性别,薪水
类就是类型,类不是个体,不是具体东西
属性:是属于对象的变量,每个对象都有一份
属性是在类上定义的
代码:类的定义
eg:class Emp{
String name;//姓名
int age;//年龄
char gender;//性别
double salary;//薪资
}
定义方法
public static int sum ( int num1 , int num2 ) { }
方法调用
int result = sum(5,6);
int a = 50, b = 60;
int result = sum ( a , b );
抽象数据类型:将不同类型的数据的集合组成一个整体用来描述一种新的事物。
类不但定义了抽象数据类型的组成,同时还定义了可以对该类型实施的操作(方法)。
使用类的目的:管理一组信息
类的定义包括“成员变量”和定义的“方法”的定义
java语言中,类的成员变量的定义可以使用如下语法,类名首字母需大写
class 类名{
成员变量类型 变量名称
}
除了基本类型都是引用类型,引用类型自动初始化为null
局部变量:在栈中分配(在循环里面声明的变量)
对象:在堆中分配
new运算在堆中开辟空间
成员变量:创建对象以后称为“对象的属性”,也就是属于对象的数据,也称为实例变量(如Cell方法中的row和col)
程序=数据+算法
new :运算符,只分配堆内存数据空间,保存数据
new 数组:分配数组空间,堆内存
new 类 :分配对象空间,堆内存,按照类的声明,按照类的属性分配内存空间
当内存不够分配的时候,会溢出(内存泄漏)、
内存:分为3个主要区域
栈:分配局部变量
局部变量:在方法中声明的变量,可以是基本类型也可以是引用类型
堆:存储对象,所有对象都在堆中。对象的属性就是在堆中分配的,属于对象的变量,对象的属性可以是基本类型也可以是引用类型
方法区:存储类的信息。class加载区域,静态区
引用类型:除了基本类型(8种基本来型),都是引用类型。
******* 引用类型 与 基本类型的差异 ********
基本类型的值 就是本身的值 eg: int a=5 //a的值就是5
引用类型的值 是一个对象的地址是 引用类型变量通过地址间接引用了对象
eg:Cell c=new Cell();
严禁说法:c的值是new创建对象的首地址, c通过这个首地址引用了堆内存中的Cell类型对象
不严禁说法:c的值是对象
当使用 赋值进行赋值的时候
Cell c2==c;
严禁说法:将c的值(地址值)赋值给变量c2,c2的值与c相同,都引用同一个对象
null值现象
应用类型特有现象,表示变量不引用任何对象的状态!此时有变量,没有对象,
如果访问值是null的引用变量的属性和方法,将发生空指针异常
空指针异常 ******背*****
1,有引用变量
2,变量值null,不引用任何对象
3,访问了变量的属性,方法,成员
满足1,2,3时候发生空指针异常
如何解决空指针异常
1,访问属性和方法之前,使引用变量合理的引用对象就可以解决空指针异常
2,在访问方格,属性,成员之前检查引用变量是否为null,如果不为null再访问
错误:
1,对象是空,会发生空指针异常!//对象不能说为空
2,变量为空,一定为发生空指针异常!//不访问就不会发生空指针异常
方法:封装计算过程
对象的方法:
1,是封装了对对象数据进行计算操作的算法
2,方法实现了定义的功能(动作)
为啥要用方法:就是封装功能,使用功能能够重用
使用方法:
在类中为对象定义方法,实现对象数据的计算功能
class Cell{
int row;
int col;
public void drop(){//下落 功能:算法当前对象的行+1
row++;
}
}
使用方法:调用方法,在对象上调用方法,实现计算功能
Cell c=new Cell();
c.row=0;
c.col=4;
c.drop();//调用对象的方法,执行下落算法
System.out.println(c.row);//1
//方法好处是可以重用
c.drop();
c.drop();
c.drop();
方法的重载:
在类中定义方法名一样,方法参数不同的方法
为啥要用重载:
为了提供方法名一样的不用功能的方法
eg:方块 有两种下落方式:1)一格一格下落,2)直接下落到底层
方法重载语法:
在类中:
1,方法名一样
2,方法参数类型列表一定不同
为Cell增加另一种下落方法,利用重载语句
class Cell{//声明了两个重载的方法drop
int row,col;
public void drop(){}//实现下落一步
public void drop(int step){}//实现下落n步
}
构造方法语法结构
构造方法是在类中定义的方法,不同于其他的方法,构造方法的定义有如下两点规则:
1,构造方法的名称必须与类名相同
2,构造方法没有返回值,但也不能写void
语法:
[访问修饰符]类名(){
构造体;
}
构造方法常用于实现对象成员变量的初始化
class Cell{
int rot,col;
public Cell(int row1,int col1){
row=row1;
col=col1;
}
}
使用调用构造器,必须使用new元素调用构造其
构造器方法:
构造器方法(构造器)与方法
1,用途不同
构造方法:初始化对象的属性
格子的构造器用于初始化格子的属性
方法:用于封装功能算法
格子的方法drop用于做下落计算。
2,语法不同:
构造方法:名字于类名一样,不能定义返回值
使用new运算符调用,用于创建对象
方法:名字一般与类名不同,必须定义返回值
使用对象引用.方法名调用。对这个对象进行计算
方法和构造方法没有关系。详见JSDMy1503_OOP/src/day02/gouzaoqi.java
this关键字
this==这个是代词,代表当前事物
this在方法运行期间代表调用方法的当前对象本身,是指当前对象的引用变量
****在方法运行期间
****指向当前对象的引用变量
this代表调用方法时的这个对象!
何时使用:
1,当“局部变量”与“实例变量(属性)”同名时候,this.实例变量方式区别于局部变量
eg:
class Cell{
int row,col;//实例变量 属性
public void drop(){
int row =1//局部变量
row //不加前缀,是局部变量
this.row//是实例变量
}
}
成员变量>=“实例变量”==对象属性
任何一个类都必须含有构造方法(构造器)。
如果源程序中没有定义,编译器在编译时将为其添加一个无参数的空构造器。
当定义了构造方法后,java编译器将不再添加默认的构造方法。
构造器可以重载
构造器名字相同,参数不同
一个类中可以定义多个构造器
为啥要构造器重载
构造器:初始化对象,方便创建对象
方便用多种方式创建对象:构造器重载
class Cell{
int roe,col;
public Cell(){//无参构造器
row=(int)(Math.random()*10+10);
col=(int)(Math.random()*10+10);
}
public Cell(int row,int col){//有参构造器
this.row=row;
this.col=col;
}
}
数组
java中没有真正的二维数组
二维数组的迭代 迭代==遍历
for(int i=0;i<arr.length;i++){
System.out.println();
for(int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]+" ");
}
}
1,内存管理:
编译好的java程序需要运行在JVM中
JVM内存分为“堆”,“栈”,“方法区”三个区域,分别用于存储不同的数据。
java创建了大量的对象,这些对象都被引用,无法被GC回收,会造成内存泄漏
2,变量的生存周期
局部变量也称为临时变量,生存周期为作用域,离开作用域时会及时销毁
java的编程习惯是,变量的作用域越小越好
成员变量:实例变量和静态变量
成员变量>=“实例变量”==对象属性
局部变量 比较 实例变量(对象属性)
局部变量:
定在方法中
没有默认值,必须自行设定初始值
方法被调用,存在栈中,方法调用结束,从栈中清楚
变量成员:
定义在类中,方法外
有默认初始值,可以不显示初始值
所在类被实例化后,存在堆中,对象被回收时,成员变量消失
方法区,存放所有的类
继承
通过extends关键字可以实现类的继承
构造器名称跟类名一样
构造器:
1,类一定有构造器
2,构造器不能继承
3,java中子类的构造器一定调用父类构造器
a,子类构造器中默认情况下自动调用父类无参数构造器(隐含规则)
b,如果父类没有无参数构造器,就必须使用super()调用父类有参数构造器
建议:凡是是类都要有构造器,方便子类的继承!
class Noo{
//public Noo(){}//****无参构造器******
public Noo(int n){
System.out.println("Call Noo(n");
}
}
class Moo extends Noo{//Moo会自动调用父类的无参构造器,但是父类没有无参构造器,出现编译错误!
//解决方法:1,在父类中添加无参构造器2,在子类构造使用super(5)调用父类有参构造器
public Moo(){
super(5);
}
}
super.的用法 2)super()//调用父类构造器
1)super. //在子类对象中父类型中声明的属性,方法
public class demo10 {
public static void main(String[] args) {
Boo boo=new Boo();
boo.test();
}
}
class Aoo{//父类int times=1;}
class Boo extends Aoo{//子类
int times=8;
public void test(){
int times=9;
//就近原则
System.out.println(times);//9
System.out.println(this.times);//8
System.out.println(super.times);//1
}
}
this也有两种用途
this, 代表当前对象,访问当前对象的属性和方法
this() 在类的构造器中调用本来的其他构造器实现构造器的重用,简化代码 eg:demo11
只能在构造器中使用,并且只能用于构造器的第一行
this()和super()互斥
父类的引用指向子类型的对象
一个子类的对象可以向上造型为父类的类型。即,定义父类型的引用可以指向字类的对象
父类的引用可以指向子类的对象,但通过父类的引用只能访问父类所定义的成员,不能访问子类扩展的对象
重写:
在java语言中,子类可以重写(覆盖)继承自父类的方法,即方法名和参数列表与父类的方法相同,但是方法的实现不同。
当子类重写了父类的方法后,该重写方法被调用时(无论是通过子类的引用调用还是通过父类的引用调用),运行的都是子类重写后的版本。
通过super.可调用父类的方法,
重写(override)重载(overload)的区别
重载:一个类在当前类中声明方法和父类中继承的方法中,方法名相同的方法,参数列表不同
重载是指在一个类中定义多个方法名相同但参数列表不同的方法,在编译时
根据参数的个数和类型来决定绑定哪个方法
1,方法名相同但参数列表不同
2,本质上完全不用
根据方法名+参数类型类表=方法签名
调用的规则:根据方法签名识别执行
重写:发生在两个类中,并且是子类和父类的父关系,子类和父类的签名相同 ,子类修改父类的行为方法
有继承为前提,如果不能继承(私有方法不能继承,),就不会发生重写,重写是指在子类中定义和父类完全相同的方法,在程序运行时,根据对象的
类型不同(而不是引用类型)而调用不同的版本
***可以通过super访问父类的方法。
1,方法名一样
2,参数列表一样
3,修饰词可以放大,保护的可以放大为公共的
4,返回值可以返回小类型(大多都一样)
5,异常可以更加小
大多情况下:子类声明方法与父类完全一样
6,调用时候:调用子类对象的重写方法
重载是看类型 在编译期绑定
重写是看对象 在运行期绑定
包的概念
定义类时需要指定类的名称,但如果仅仅将类名作为类的唯一标识,则不可避免的出现命名冲突的问题,这会给组件及团队的合作造成很大的麻烦
包名也可以有层次结构,在一个包中可以包含另外一个包,
import语句语法:import类的全局限定命名()
package day04;
import day04.sub.Point;
public class dome05 {
/**
* 在day04中访问day04.sub包中声明Point
* dome05和Point不在同一个包中
*/
public static void main(String[] args) {
//1)使用全名限定名(类的全名)访问类
day04.sub.Point p=new day04.sub.Point(5,6);
//2)使用import导入day04.sub.Point导入以后就可以省略包名
Point p2=new Point(7,8);//以上两种方式都可以实现跨包访问类
//2)import更加方便
//1)何时使用:当前包中的类于导入的类重名,只能使用1)方式
Moo m=new Moo();//就近原则,m使用了本包中的Moo类
day04.sub.Moo m2=new day04.sub.Moo();//使用day04.sub包中的Moo类
}
}
class Moo{
}
访问修饰符:
封装的意义:
1,降低代码出错的可能性,更便于维护。
2,当内部实现细节改变时,只要保证对外的功能定义不变,其他的模块不需要更改。在软件系统中,封装常常需要依靠一些访问控制修饰符来实现。
private与public为最最常用的两个访问控制修饰符
private修饰的成员变量和方法仅仅只能在本类中调用
protected修饰的成员变量和方法可以被子类及同一个包中的类使用
默认访问控制即不书写任何访问控制符,默认访问控制的成员变量和方法可以被同一个包中的类调用
public修饰的成员变量和方法可以在任何地方调用
私有的目的:是封装,保护
修饰词使用原则
1,尽可能使用private修饰属性和方法,尽量封装在清楚该用哪个修饰词时候,首先用private
2,如果是给子类留下属性或方法,使用protected
3,确实是公共属性或方法,需要被其他类访问的时候使用public
4,默认的修饰词,尽量不用,几乎不用
总之:尽量封装
public protected 默认 private
多态:
各种各样的情况都会发生!
static修饰成员变量
1,在类中使用static修饰的成员变量
2,类加载期间在方法区初始化
3,在软件运行期间,只有“一份”的变量
4,一般使用类名,变量名访问静态变量,很少使用对象.变量名访问静态变量
5,静态变量(静态变量成员)称为属于类的变量,是类的全体实例共享的同“一份”变量
6.凡是软件运行期间的“一份”数据可以使用静态变量存储
它所修饰的成员变量不属于对象的数据结构,而是属于类的变量,通常通过类名来引用static成员。
当创建对象后,成员变量是存储在堆中的,而static成员变量和类的信息一起存储在方法区, 而不是在堆中
在static方法中也不能访问非static成员(对象成员)
成员变量:
1,实例变量:是属于对象的变量
2,静态变量:是属于类的变量,只有“一份”。
静态方法:
1,属于类的方法
2,一般使用类名.方法名
3,不需要创建对象直接类名.方法名
优点:使用方法名直接调用方法,不用创建对象直接执行方法,调用方便eg:Math.random;
非静态方法:
优点:可以使用当前对象的数据
必须使用对象调用,当前对象默认传递this作为当前对象数据
大多使用非静态方法,方便计算,确实与当前对象无关的对象,在使用静态方法
因为静态方法中没有当前对象的引用this,在静态方法中不能直接访问当前的对象的属性,方法。
静态方法中没有this
使用建议
1,当一个方法在运行期间“使用了当前对象的数据”(this)时候这个方法,这个方法要声明为非静态
2,当一个方法在运算期间与当前对象数据(属性)无关,这个方法就可以声明为静态方法
eg:计算一个整数是否是10的倍数,是静态还是非静态。计算过程于任何对象无关所以可以定为静态放法
******** 与当前对象无关用静态 ******
静态方法:属于类的,于当前对象昂无关方法
static块
static块:属于类的代码块,
静态代码块,在类中声明的语句块!静态代码块中可以使用任何语句
在类加载期间执行,因为java类只加载一次,所以静态代码块只执行一次
用于:加载一次性资源(图片,声音等)
class Apple{
static{//静态代码块,在类中声明的语句块!静态代码块中可以使用任何语句
//在类加载期间执行,因为java类只加载一次,所以静态代码块只执行一次
System.out.println("Hello Apple!");
}
}
final关键字
final修饰的成员变量,意为不可改变,初始化后不可改变
两种初始化方式:
1,声明变量同时初始化
2,使用赋值语句第一次赋值,初始化
3,使用构造器初始化
4,方法调用时候参数传递初始化
final关键字也可以修饰局部变量,使用之前初始化即可
final关键字修饰的方法不可以被重写:防止子类在定义新方法时造成的“不经意”重写
final关键词修饰的类不能被继承
final的优点:
1,可以保护变量的值不被修改
2,可避免意外被改变出现的错误
3,可以保护类不被继承修改,可以监制滥用继承对系统造成的危害
final:初始化以后不可以再改变
static:使用类只有“一份”
jdk中的一些基础类库被定义为final的,eg:String,Math,Integer,Double等等
static final常量
static final 修饰的成员变量称为常量,必须声明同时初始化,并且不可被改变。常量建议所有字母大写。
一个类如果没有父类,就继承Object,任何类的最终父类都继承于Object
任何类型都是Object:啥都是东西====一切皆对象(唯物主义)
<--:是
|<--坦克
|<--交通工具|
Object| |<--汽车
|< --Cell
抽象类(abstract):抽象类不可以实例化,即不可以new
抽象方法可以有参数,有返回值
抽象类只能被继承,(就是用来被继承的)
abstract和final关键字不可以同时用于修饰同一个类,
一个类继承抽象类后,必须重写其抽象方法,不同的子类可以有不同的实现
一个程序中只有一个公有类 public class mingzi
即使一个类中没有抽象方法,也可以定义为抽象类
总结:
1,如果泛化出方法无法确定方法体 不写方法体,声明为抽象方法
2,包含抽象父那个法的类,一定抽象类
3,抽象类不能直接实例化,创建对象
4,抽象类只能作为父类被继承
5,在继承抽象类型时候,必须重写与(实现)其抽象方法。
优点:
就限制了这个类的实例化,有些类如果能实例化,结果有害的
eg:Tetromino就是不能被创建实例的类
可以创建它的子类型对象:T S L J...
abstract class Tetromino{....}
Tetromino本身是一个半成品,不应用new
在软件中,凡是泛化出的继承根,用于共享子类 公共部分的父类,应该说明为抽象类!
抽象方法:没有方法体的方法,由abstrct修饰
是子类方法的约定,是契约。
凡是要约定子类必须就有哪些方法,就可以通过定义抽象方法进行约定
接口:
接口可以看成是特殊的抽像类,即只包含有抽象方法的抽象类
接口中不可以定义成员变量,但可以定义常量
与继承不用,一个类可以实现多个接口,实现的接口直接用逗号隔开,
可以通过interface关键字来定义接口
interface Runner {
public static int DEFAULT_SPEED = 100
public void run();
接口就是一个标准,一个规范
接口中只能包含常量和抽象方法
接口不能被实例化
接口子类的范围必须大于等于父类
若类又继承父类又实现接口,需先继承后实现
class Coo extends Abc implements IInter,IInter2 {//先继承后实现
接口与接口之间可以继承
interface IInter1{
double PI=.014159;
int NUM=5;//默认public static final
public abstract void shou();
void say();//默认public abstract
//int NUM2://常量必须同时声明初始化
}
接口与接口是继承关系,用extends继承
类与接口是实现关系,用implements实现
多态:
1,父类型引的子类实例,是多种多样的
2,执行子类型方法,执行结果松多种多样的
一个类型的引用在指向不同的对象时有不同的功能
同样一个对象,造型成不同类型时,具有不同的功能
父类型引用的对象可以是各种子类对象
同一个引用在对象不同的时候,调用的方法也不同
java语法规定:引用变量是什么类型,就只能在这个引用上访问那些方法,属性
1)java规定什么类型调用其声明的方法,和属性
2)如果当前类型变量没有对象声明方法利用强制转换型,将变量转换为包含方法的类型,就可以执行方法了
向上造型:
父类型变量(类,抽象类,接口)声明变量可以引用子类型实例
一个类的对象可以向上造型的类型有:
1,父类的类型
2,其实现的接口类型
能点出什么看类型
强制转型
子类小,父类大
实现类小,接口大
1,可以通过强制转换将父类型变量转换为子类型变量,前提是该变量指向的对象确实是该子类类型
2,也可以通过强制转换将变量装换为某种接口类型,前提是该变量指向的对象确实实现了该接口
关键字instanceof判断引用指向的对象是否为指定类型
boolean b1=f/*变量*/ instanceof Award/*类,接口*/;//false
强制转型本身不安全,如果先预测风险,没有风险再转换,有风险不转换,就安全了,先检查类型,如果类型是兼容的再进行转换就是安全的类型转换
经典写法:
if(f instanceof Award){
Award a=(Award)f:
System.out.println(a.getAwardType());
}
instanceof为true两种情况
1)对象为该类型
2)对象实现了该接口
强制转型:两种情况
1)被转换的变量引用的对象,实现(继承)了目标类型,是目标类型的子类型,转换会成功
2)被转换的变量引用的对象,没有实现(继承)目标类型,不是目标类型的子类型,转换失败。抛出ClassCastException异常
强转时看对象
内部类
1,一个类可以定义在另外一个类的内部,定义在类内部的类称之为Inner,其所在的类称之为Outer
2,Inner定义在Outer的内部,通常只服务于Outer类,对外部不具备可见型,Inner可以直接调用
outer的成员及方法(包含私有的)。
一般情况下,Inner对象会在Outer对象中创建(构造方法或者其他方法);Inner对象中会有
一个隐式的引用指向创建他的Outer类对象
内部类,一个类只被一个类使用,对外不可见
内部类对象通常只在外部类中被创建,内部类中可以直接访问外部类的所有成员
1,内部类只为外部类来使用,其他类不用
2,内部类可以直接访问外部类的所有成员,默认有个隐式的指向外部对象的Mama.this.
3,内部类通常只在外部类中被创建(new)
匿名内部类
如果在一段程序中需要创建一个类的对象(通常这个类需要实现某个接口或者继承某个类)
而且对象创建后,这个类的价值也就不存在了,这个类可以不必命名,称之为匿名内部类。
1,何时用:有一个类(子类或实现类),只需创建一个对象,对象创建完,这个类就没有意义了
//不使用匿名内部类
interface Inter{
}
class Aoo implements Inter{
}
main(){
Aoo o=new Aoo():
}
//使用匿名内部类
interface Inter{
}
main(){
Inter o=new Inter(){实现类的成员};
}
匿名内部类优点:
1;封装:类的声明封装到方法中
2,简介:使用简练,经常用于继承类,抽象类实现接口,使用内部类
3,共享:外部对象的资源,可以共享方法中局部变量,java要求这个局部变量必须是final的缺点
不是完整功能:没有构造器重载!
小结:
面向对象3大特征:
1,封装:
类:封装数据,行为
作为一个整体操作
方法:封装功能的实现
隐藏实现的细节
访问修饰符:控制访问权限
保证数据的安全
2,继承:实现代码的重用
extends
3,多态:多种形态,在继承的基础之上
提高可维护型,可拓展型
1)一个类型指向不用的对象,有不用的实现
2)同一个对象造成不同类型,有不同功能
//for(int i=0;i<cells.length;i++){
//Cell c=cells[i];
//foreach循环,用途,简单替换上述代码
for(Cell c:cells){//等价于上两行,java1.5以上版本提供