Java-Review-Note——2.面向对象
标签: JavaStudy
面向对象理解
对象引入:
所有事物都具有两个方面,有什么,能做什么,可以理解为这两点:
属性(描述对象) 和 方法(对象功能)
对象设计的要求:高内聚,低耦合,从而提高对象的可复用性
对象设计的思想:以对象为中心,先开发类,得到对象,再通过对象间的相互通信实现功能
面向对象的几个基本概念:
- 对象:人们要进行研究的任何事物
- 类:具有相同或相似性质的对象的抽象
- 对象的状态与行为:数据与相应的操作
- 类的结构:类间的结构关系,"一般---具体 is a"继承关系,和"整体---部分" has a"聚集关系
面对对象的方式:ADP
OOA(分析):产生系统的类和对象,描述软件要做什么
OOD(设计):OOA的细化,强调复杂系统的正确和有效构建,即确定类间的关系,
对象间的关系,类的状态转换,模块间的依赖等,软件怎么做
OOP(编码):三个标准条件:
1.使用对象而非算法作为基本逻辑组件;
2.任意对象都需为某个类的实例
3.类通过继承关系与其他类相关
面向对象的四大特征:
- 封装(Encapsulation):隐藏对象的实现细节,通过公有方法暴露对象功能
- 多态(Polymorphism):子类对象可以直接赋值给父类,但运行时表现出子类的行为特征
-
继承(Inheritance):一个类共享一个或多个类定义的结构与行为,
表示一种泛化/特化的层次关系 -
抽象(Abstraction):忽略主题中与当前目标无关的方面,以便更充分地注意与
当前目标有关的方面,包含过程抽象与数据抽象。
对象
如何创建对象:new关键字 + 指定类名创建
对象的产生:堆中建立对象 -> 栈中创建一个变量引用对象地址
对象与对象的引用:
对象名作为操作的标识符,仅仅只是对象的一个引用而已,而并非对象本身;
有引用,但不表示一定要有一个对象与引用项链,所以在创建一个引用时,
都需要进行初始化,不初始化直接调用的话是会NullPointerException的。
对象的使用:通过点语法访问.eg:p.age = 18;
对象的生命周期:从new创建开始,到没有任何引用到达对象时结束(成为垃圾)
匿名对象的使用:
不定义变量引用对象,用new创建后直接调用,没名字,所以叫做匿名对象
通常我们需要使用一对象,且只用一次的话,就用匿名对象(没有引用,
使用一次后就变成垃圾了)可以作为实参进行传递
类
类与对象的建模过程:
类的定义:
修饰符 class 类名
{
成员变量
构造方法
成员方法
}
成员变量,局部变量与类变量区别:
成员变量:定义在类中,在整个类中都可以访问,存在于栈内存的对象中,
随着对象的消失而消失,有默认初始值。
局部变量:定义在方法,语句,局部代码块中,只在所属区域有效;
存在栈内存的方法中,随所属区域的执行而执行;结束而释放,没有默认初始值。
类变量:static修饰,随者类加载而加载,类消失而消失,类变量是所有
对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果
成员变量的初始化:
当对象创建时,会对成员变量自动赋初值,基本数据位0,引用型为null;
注:char为"\u0000"表空 boolean:false
构造方法(Constructor):
为对象进行初始化的一个特殊方法,在生成对象时会被调用来初始化对象
构造方法名与类名相同,new对象时隐式地进行调用,用户无法显式调用;
无返回值,不能加void返回值类型,总会有的,就算你不写构造方法;
也会自动生成默认缺省的构造方法;当然如果写了,就不会再生成了默认的。
构造代码块:
直接在类中定义切没有加static关键字的代码块,在创建对象时会被调用,
每次创建对象都会被调用,并且先于构造方法执行.
普通代码块:
在方法或者语句中出现的代码块,先出现先执行
静态代码块:
添加了static声明的代码块,一般用于初始化类,为类属性初始化;
会随着JVM加载类的时加载而执行,所以只执行一次;
不能存在于任何方法体中,不能直接访问静态实例变量和方法,
需要通过类的示实例对象来访问
this关键字:
作用:1.区分局部变量和实例变量;2.代表本类对象
3.显式调用重载的构造方法,调用语句需写在第一行
比如:
public class Test {
int a;
public Test(){this(1);}
public Test(int i){this.a = i;}
}
成员方法:
一个好的方法应该有好的移植性和可重用性
两种传参方式:
①按值传递:内存的空间变量 eg:int i
②按引用传递(传对象引用):Integer类的一个对象引用: Integer i = new Integer(10);
public修饰类的规则:
一个Java文件,只允许有一个修饰为public的类,接口,枚举(enum),
且名字要与文件名相同,不然编译器会报错!
包的概念:
打包:package eg: package com.jay.example;
导包:import eg:inport java.io.;
注意:导包时用星号只表示该层次的所有类,但是不包含子层次下的类*!
继承
继承的理解:
比如:学生,公务员,城管,警察,他们的共性都是人类,我们把人类作为父类,
而把他们作为人类的子类,拥有人类的所有属性,同时也衍生了一些自己的特性,
比如,城管具有暴力执法的特性。
继承的方式:子类 extends 父类: eg:class Student extends Person{}
继承的注意事项:
- 1.Java的数据结构是树形的,所以不像C++可以继承多个父类,只能单继承;
Java通过接口和内部类实现多继承! - 2.父类的私有属性也继承,但是不可以直接访问,只能通过父类方法进行访问;
- 3.子类如果想调用父类的构造方法要使用super(参数),不然会提示找不到!
其他成员方法用super.xxx访问。 - 4.Object类是所有类的父类。
- 5."先有父亲,后有儿子"创建子类对象后,不用我们自己实例化父类对象,系统
会自动创建一个父类对象
子类构造对象的顺序:
- 从父类到子类,对static成员进行初始化;
- 父类成员变量按顺序初始化,递归调用父类的构造方法
- 子类成员变量按顺序初始化,子类构造方法调用
super关键字:
需注意:子类中访问父类的同名成员,用super语句向父类构造方法传,
那么super(参数)方法要放在第一句,不然会报错。
多态
OverLoading:编译时多态(方法重载)
同一个类可定义多个同名方法,各个方法的参数表一定不同(参数个数或类型不同),
返回值也可以不同,比如:构造方法的重载就是编译时的多态。
OverRidding:运行时多态(方法重定义/覆盖)
运行时多态 = 继承 + 重定义 + 动态绑定
方法覆盖:
子类方法与父类方法名,参数表,返回值类型相同
规律:不能回避比父类方法更多的异常,子类访问控制需比父类更公开
向上转型规则(UpCasting)
Animal a = new dog(); Dog d = (Dog)a;
问:如果调用a的叫方法,那么调用的是Animal的叫还是Dog的叫?
答:Dog的,new后面是什么类型,动态类型就是什么类型。
内部类
内部类:在一个类中又定义了一个类,外面的叫外部类,里面的就叫内部类,分以下四种:
成员内部类,静态内部类,局部内部类,匿名内部类
使用内部类的目的:内部类可以直接访问外部类的成员和方法
注意事项:访问内部类的话需要先创建外部类对象,接着才可以用它来创建内部类对象。
成员内部类:
class Outer {
void showInner(){Inner in = new Inner(); in.show();}
class InnerP{
void show(){...}
void test(){...}
}
}
//测试类:
public class InnerTest {
public static void main(String[] args){
Outer out = new Outer();
Outer.Inner in = out.new Inner(); //注意这里的写法
in.test();
}
}
静态内部类:
静态内部类只能访问外部类的静态成员;
创建内部类对象不需要外部对象,直接:new 外部类名.内部类的构造方法
class Outer{
public static int NUM = 250;
public void outerShow();
static class Inner(){
void innerShow(){ System.out.println("NUM:" + NUM); }
}
}
//测试类:
public class StaticTest{
public static void main(String[] args){
Outer out = new Outer();
out.outerShow();
Outer.Inner in = new Outer.Inner();
in.innerShow();
}
}
局部内部类:
局部内部类是存在于类中的某个局部,可能是在某个方法或者某个块语句中
是用的最少的一种内部类,和局部变量一样,不能够被public,protected,private
和static修饰只能够访问方法中定义的final类型的局部变量
只能够在方法中生成局部内部类的对象并且调用它的方法
class Outer{
int a = 1;
public void show(){
int b = 2;
final c = 3;
class Inner{
public void show(){
System.out.println(a); //可以访问外部类中的变量
System.out.printf(b); //会报错
System.out.println(a); //可以访问方法中的final变量
}
}
new Inner().show(); //需在方法中实例化内部类对象
}
}
//测试类
public class LoaclTest{
Outer out = new Outer();
out.show();
}
匿名内部类:
没有名称的内部类,必须是非静态的类,只能用一次;
通常是隐式地继承一个父类或者实现一个接口
一般用来简化代码编写
//实现抽象方法可以省略一个子类编写(接口亦是如此)
abstract class A{ public abstract void show(); }
//调用出直接:
A a = new A(){
public void show(){...}
}
a.show();
比如我们,Android点击事件的时候我们也常这样写:
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) { ... }});
})
抽象类
什么是抽象类:
将具有共同特点的类进行抽象后得到的一个类,这个类本身的方法没有任何具体实现;
比如:定义一个抽象的动物类,然后定义几个抽象方法(动物共有的方法),比如有设置
多少只脚的方法:public abstract void setFoots();
抽象类的定义:
使用abstract关键字修饰
抽象类: 修饰符 abstract 类名{//类的内容}
抽象方法: 修饰符 abstract 返回值类型 方法名();
抽象类的注意事项:
- 1.如果一个类有一个抽象方法,那个这个类一定是抽象类。
- 2.虽然一个类是抽象类,但可能含非抽象的方法。
- 3.如果类继承了抽象类,必须重写抽象类中所有的抽象方法,是所有!如果
没有全部实现的话,子类也需要定义为抽象类。 - 4.abstract不能和static一起使用,会出现错误(因为static不能被覆盖,而
abstract必须被覆盖)。 - 5.抽象类不能定义为final,abstract不能喝final共存。
- 6.注意区分方法的空实现和方法的抽象(无实现)!例子如下:
前者:private void show(){} 后者:private void show(); - 7.抽象类不能够实例化,但是可以new的时候重写里面的抽象方法(匿名内部类),
或者通过向上转型规则:Car c = new Track(); 这样。
接口
什么是接口?
因为Java的数据结构是树型的,所以不像C++那样可以同时继承多个父类;
但是Java通过接口和内部类实现了多继承;接口是一种特殊的抽象类,
一个类实现一个接口,相当于他继承了一个抽象类。
接口的定义:修饰符 interface 接口名{"内容"}
接口的实现:
一个类可以在继承一个父类的同时实现多个接口,用","分隔:
class 类名 extends 父类 implements 接口1,接口2 { ... }
接口的注意事项:
- 1.一个Java文件中只允许有一个public修饰的类,接口,枚举,且需与文件名同名。
- 2.在一个接口中,所有方法都是公开的,抽象的!所有属性都是公开,静态,常量!
- 3.如果一个类生命实现一个接口,但是没有实现接口中的所有方法,那么这个类必须是抽象类!
- 4.接口只关心功能,并不关心功能的具体实现。
- 5.接口也可以通过extends继承,但是实现接口时父类子类中所有的抽象方法都需要实现。
- 6.接口中的方法可以不写public,但是实现接口中的抽象方法时需要写上public,不然会报错!
修饰符详解
访问控制修饰符
- public:公有的,被public修饰的部分可以被任何程序访问。
- protected:受保护的,被它修饰的成员只能由同包中的类或者其子类访问。
- default(默认):不写修饰符就是默认的,别写上defalut啊!同包与同类可见。
- private:私有的,是Java实现封装的关键,被修饰的成员变量与方法只能被类本身访问,同包也不行!
注意事项:不能使用protected和private来修饰类,要么用public,要么不加修饰符!
static修饰符:
- 1.随着类的加载而加载,优先于对象存在,被所有的对象所共享,直接被类名所调用
- 2.静态变量:static修饰的变量在所有对象中是共享的,指向内存中同一地址,即任何
对象对变量值的修改都会是存储空间的值发生改变。 - 3.静态方法:只能够访问静态数据或者直接调用静态方法,可以直接通过类名进行调用
- 4.静态代码块:放在类声明的内部,成员方法与构造方法的外部,该代码块会在该类第
一次使用时执行一次,就不会再执行了,通常是在这里写一些初始化的代码。 - 5.成员初始化的顺序:(静态变量,静态初始化块)->(变量,变量初始化块)->(构造器)
final修饰符:
- 1.修饰常量:public static final int AGE = 10;
- 2.空白final变量:空白的final数据成员须在构造方法中进行初始化,否则会报错。
- 3.final常量作为方法的参数,只能够对final进行简单的引用,不能改变常量的值。
- 4.用final来修饰方法:那么该方法为一个不可覆盖的方法,如果父类有final修饰的方法,
那么子类继承同一个方法 - 5.用final来修饰类:那么该类不可以被继承,final类没有子类;同时该类中所有的
方法都默认为final! - 6.final并不涉及继承,继承取决于类的修饰符是public还是其他,是否可以继承取决于
该类是否对其子类可见,如果一个方法前有private或static的修饰符,那么系统会在前面自动地
加上final修饰。
abstract抽象修饰符:被abstract修饰的类为抽象类,修饰的方法为抽象方法。
transient:用于修饰不想序列化,持久化的成员
volatile:保证可见性和防止重排序,用的比较少,线程并发用到。
枚举类型
可以把枚举enum看成一个普通的类,只是编辑器帮我们做了语法的解析
与编译而已,你也可以定义一些属性和方法,但是不能继承其他类,因为
已经继承了java.lang.Enum;
简单用法:(做标记,switch的时候用到)
public enum Color { BLUE,RED,YELLOW; }
//测试类
public EnumTest{
public static void printColor(Color color) {
switch(color) {
case BLUE: System.out.println("蓝色"); break;
case RED: System.out.println("红色"); break;
case YELLOW: System.out.println("黄色"); break;
}
}
public static void main(String[] args) {
printColor(Color.BLUE);
printColor(Color.RED);
printColor(Color.YELLOW);
//也可以用增强for循环遍历所有值,调values()可以获得枚举数组
for(Color c : Color.values()){ System.out.println(c); }
}
}
自定义属性方法:
public enum Color {
Red("红色"),BLUE("蓝色"),YELLOW("黄色");
private final String value; //私有定义一个成员变量
Color(String value){ this.value = value; } //构造方法
public String getValue() { return value; } //定义一个获取后面值的方法
}
//测试类
public class EnumTest{
public static void main(String[] args) {
//可以通过for循环调用获得枚举中所有的值
for(Color color : Color.values()) {
System.out.println(color);
System.out.println(color.getValue());
}
//可以调用ordinal()获得枚举值在枚举中的索引位置,从0开始的
System.out.println(Color.BLUE.ordinal());
//枚举默认实现了java.lang.Comparable接口,可以直接调用compareTo对枚举值进行比较
System.out.println(Color.Red.compareTo(Color.BLUE));
}
}
结果:RED 红色 BLUE 蓝色 YELLOW 黄色 1 -1