Java 学习笔记 面向对象

基本语法

面向对象(一)

类及对象

类的组成成分:

  1. 属性(成员变量,Field)
  2. 方法(成员方法,函数,Method)
属性

关于变量的分类:

  1. 按照数据类型的不同:基本数据类型(8种)& 引用数据类型
  2. 按照声明的位置的不同:成员变量 & 局部变量

成员变量与局部变量异同点:

相同点:

  1. 遵循变量声明的格式: 数据类型 变量名 = 初始化值
  2. 都有作用域

不同点:

  1. 声明的位置的不同。成员变量:声明在类里,方法外;局部变量:声明在方法内,方法的形参部分,代码块内。
  2. 成员变量的修饰符有四个:public private protected 缺省;局部变量没有修饰符,与所在的方法修饰符相同。
  3. 初始化值:一定会有初始化值。局部变量:一定要显式的赋值。(局部变量没有默认初始化值);成员变量:如果在声明的时候,不显式的赋值,那么不同数据类型会有不同的默认初始化值。
    • byte short int long ==>0
    • float double ==>0.0
    • char ==>空格
    • boolean ==>false
    • 引用类型变量==>null
  4. 二者在内存中存放的位置不同。成员变量:存在于堆空间中;局部变量:栈空间中。
方法

提供某种功能的实现。

1> 格式:权限修饰符 返回值类型(void:无返回值/具体的返回值) 方法名(形参) {}, 示例如下:

1
2
3
public void eat(){//方法体}
public String getName(){}
public void setName(String n){}

2> 关于返回值类型:

  • void:表明此方法不需要返回值
  • 有返回值的方法:在方法的最后一定有 return + 返回值类型对应的变量
  • 记忆:void 与 return 不可以同时出现一个方法内。像一对“冤家”。

3> 方法内可以调用本类的其他方法或属性,但是不能在方法内再定义方法!

面向对象编程的思想的落地法则一

1> 设计并创建类及类的成分
2> 实例化类的对象
3> 通过 对象.属性对象.方法 的形式完成某项功能

类的初始化的内存解析

内存划分的结构:

  • 栈(stack):局部变量 、对象的引用名、数组的引用名
  • 堆(heap):new 出来的 “东西”(如:对象的实体,数组的实体),含成员变量
  • 方法区:含字符串常量
  • 静态域:声明为 static 的变量

方法的重载

要求:

  1. 同一个类中
  2. 方法名必须相同
  3. 方法的参数列表不同(①参数的个数不同②参数类型不同)
  4. 方法的重载与方法的返回值类型没有关系

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//如下的四个方法构成重载
//定义两个int型变量的和
public int getSum(int i,int j){
return i + j;
}
//定义三个int型变量的和
public int getSum(int i,int j,int k){
return i + j + k;
}
//定义两个double型数据的和
public double getSum(double d1,double d2){
return d1 + d2;
}
//定义三个double型数组的和
public void getSum(double d1,double d2,double d3){
System.out.println(d1 + d2 + d3);
}

//不能与如上的几个方法构成重载
public int getSum1(int i,int j,int k){
return i + j + k;
}
public void getSum(int i,int j,int k){
System.out.println(i + j + k);
}

//以下的两个方法构成重载。
public void method1(int i,String str){
}
public void method1(String str1,int j){
}

可变个数的形参的方法

可变个数的形参的方法:

  1. 格式:对于方法的形参: 数据类型 … 形参名
  2. 可变个数的形参的方法与同名的方法之间构成重载
  3. 可变个数的形参在调用时,个数从0开始,到无穷多个都可以。
  4. 使用可变多个形参的方法与方法的形参使用数组是一致的。
  5. 若方法中存在可变个数的形参,那么一定要声明在方法形参的最后。
  6. 在一个方法中,最多声明一个可变个数的形参。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//如下四个方法构成重载
//在类中一旦定义了重载的可变个数的形参的方法以后,如下的两个方法可以省略
public void sayHello(){
System.out.println("hello world!");
}
public void sayHello(String str1){
System.out.println("hello " + str1);
}
//可变个数的形参的方法
public void sayHello(String ... args){
for(int i = 0;i < args.length;i++){
System.out.println(args[i] + "$");
}
//System.out.println("=====");
}

//public void sayHello(String ... args,int i){ //错误写法
public void sayHello(int i,String ... args){
System.out.println(i);
for(int j = 0;j < args.length;j++){
System.out.println(args[j] + "$");
}
}

public void sayHello1(String[] args){
for(int i = 0;i < args.length;i++){
System.out.println(args[i]);
}
}

java的值传递机制

面向对象的特征一:封装性

构造器

this关键字

package & import

面向对象(二)

面向对象的特征二:继承性

为什么要有继承

####

关键字super

子类对象实例化的全过程

面向对象的特征三:多态性

Object类

特点

  1. java.lang.Object 类,是所有类的根父类!
  2. Object 类仅有一个空参的构造器 public Object(){ }

关于equals()方法:

equals(Object obj)

1
2
3
 public boolean equals(Object obj) {
return (this == obj);
}

1> 基本数据类型:根据基本数据类型的值判断是否相等。相等返回 true,反之返回 false
注:两端数据类型可以不同,在不同的情况下,也可以返回 true。
2> 引用数据类型:比较引用类型变量的地址值是否相等。

equals():

  • ①只能处理引用类型变量 ②在 Object 类,发现 equals() 仍然比较的两个引用变量的地址值是否相等
  • String 包装类 FileDate 类这些重写 Object 类的 equals() 方法,比较是两个对象的”实体内容”是否完全相同。
  • 若我们自定义一个类,希望比较两个对象的属性值都相同的情况下返回 true 的话,就需要重写 Object 类的 equals(Object obj) 方法

关于toString()方法

当我们输出一个对象的引用时,会调用 toString() 方法.

1
2
3
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

注1:当我们没有重写 Object 类的 toString() 方法时,打印的就是对象所在的类,以及对象实体在堆空间的位置
注2:一般我们需要重写 Object 类的 toString() 方法,将此对象的各个属性值返回。
注3:像 StringDate File 类、包装类都重写了 toString() 方法。

包装类 Wrapper

什么是包装类

基本数据类型由于不是类,不能够使用 java 类库里提供的大量的方法。所有在设计上,
我们让每一个基本数据类型都对应一个类,同时数据存储的范围还不变。此时相当于
基本数据类型就具有了类的特点。这些类即为包装类(wrapper 或封装类)

基本数据类型 包装类
boolean Boolean
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double

基本数据类型、包装类、String类之间的转换

基本数据类型 -> 包装类:

  1. 通过构造器:Integer t = new Integer(ll)
  2. 通过字符串参数:Float f = new Float(“32.1F”)
  3. 自动装箱

包装类 -> 基本数据类型:

  1. 调用包装类的方法:xxxValue()
  2. 自动拆箱

String类 -> 包装类:
参考 基本数据类型 -> 包装类

包装类 -> String类:

  1. 包装类对象的 toString() 方法
  2. 条用包装类的 toString(形参)

基本数据类型 -> String类:

  1. String 类的 valueOf(3.4f) 方法
  2. 23.4 + “”

String类 -> 基本数据类型:

  1. 调用相应包装类的 parseXxx(String) 静态方法
  2. 通过包装类的构造器:boolean b = new Boolean(“true”)

面向对象(三)

static 关键字

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过 new 关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。

static:静态的,可以用来修饰属性、方法、代码块(或初始化块)、内部类

static 修饰属性(类变量):

  1. 由类创建的所有的对象,都共用这一个属性
  2. 当其中一个对象对此属性进行修改,会导致其他对象对此属性的一个调用。vs 实例变量(非static修饰的属性,各个对象各自拥有一套副本)
  3. 类变量随着类的加载而加载的,而且独一份
  4. 静态的变量可以直接通过 类.类变量 的形式来调用
  5. 类变量的加载是要早于对象。所以当有对象以后,可以 对象.类变量 使用。但是 类.实例变量 是不行的。
  6. 类变量存在于静态域中。

static 修饰方法(类方法):

  1. 随着类的加载而加载,在内存中也是独一份
  2. 可以直接通过 类.类方法 的方式调用
  3. 静态方法内部可以调用静态的属性或静态的方法,而不能调用非静态的属性或方法。反之,非静态的方法是可以调用静态的属性或静态的方法
  4. 静态的方法内是不可以有 this 或 super 关键字的!
  5. 静态的结构 ( static 的属性、方法、代码块、内部类 ) 的生命周期要早于非静态的结构,同时被回收也要晚于非静态的结构

单例 Singleton 设计模式

概念

设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为 private,这样,就不能用 new 操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。

java示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//饿汉式1
class Singleton{
//1.私有化构造器,使得类的外部不能够调用此构造器
private Singleton(){}
//2.创建类的对象,同时设置为private的,通过公共的方法调用,体现封装性
//3.要求此对象也为static的
private static Singleton instance = new Singleton();
//4.此公共的方法,必须为static
public static Singleton getInstance(){
return instance;
}
}

//饿汉式2
class Singleton{
//1.私有化构造器,使得类的外部不能够调用此构造器
private Singleton(){}
//2.创建类的对象,同时设置为private的,通过公共的方法来调用,体现封装性
//4.要求此对象也为static的
private static Singleton instance = null;
static{
instance = new Singleton();
}
//3.此公共的方法,必须为static
public static Singleton getInstance(){
return instance;
}
}

//懒汉式
class Singleton{
private Singleton(){}
private static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){//可能存在线程安全问题的!
instance = new Singleton();
}
return instance;
}
}

main() 方法

格式

1
2
3
public static void main(String[] args){
//方法体
}

要点

  1. main()是一个方法,是主方法,为程序的入口
  2. 权限修饰符:public protected 缺省 private —面向对象的封装性
  3. 对于方法来讲:static final abstract
  4. 方法的返回值:void / 具体的返回值类型(基本的数据类型 & 引用数据类型),方法内部一定要有return
  5. 方法名:命名的规则:xxxYyyZzz。给方法命名时,要见名之意
  6. 形参列表:同一个方法名不同的形参列表的诸多个方法间构成重载。 形参 & 实参—方法的参数传递机制:值传递
  7. 方法体:方法定义的是一种功能,具体的实现由方法体操作。

代码块

  • 代码块:是类的第4个成员
  • 作用:用来初始化类的属性
  • 分类:只能用static来修饰

静态代码块:

  1. 里面可以有输出语句
  2. 随着类的加载而加载,而且只被加载一次
  3. 多个静态代码块之间按照顺序结构执行
  4. 静态代码块的执行要早于非静态代码块的执行。
  5. 静态的代码块中只能执行静态的结构(类属性,类方法)

    非静态代码块:

  6. 可以对类的属性(静态的 & 非静态的)进行初始化操作,同时也可以调用本类声明的方法(静态的 & 非静态的)
  7. 里面可以有输出语句
  8. 一个类中可以有多个非静态的代码块,多个代码块之间按照顺序结构执行
  9. 每创建一个类的对象,非静态代码块就加载一次。
  10. 非静态代码块的执行要早于构造器

关于属性赋值的操作:
①默认的初始化
②显式的初始化或代码块初始化(此处两个结构按照顺序执行)
③构造器中;
—————以上是对象的属性初始化的过程—————
④通过方法对对象的相应属性进行修改

final 关键字

final:最终的 ,可以用来修饰类、属性、方法

  1. final修饰类:这个类就不能被继承。如:String类、StringBuffer类、System类
  2. final修饰方法:不能被重写。如:Object 类的 getClass()
  3. final修饰属性:此属性就是一个常量,一旦初始化后,不可再被赋值。习惯上,常量用大写字符表示。此常量不能使用默认初始化,但是可以显式的赋值、或者在代码块或构造器中赋值。
  4. 变量用static final修饰:全局常量。比如:Math 类的PI

注:final 与finally finalize() 区分开

抽象:abstract

使用规则

关键字 abstract 可以用来修饰类、方法

  1. abstract 修饰类:抽象类

    • 不可被实例化
    • 抽象类有构造器 (凡是类都有构造器)
    • 抽象方法所在的类,一定是抽象类。
    • 抽象类中可以没有抽象方法。

    注:当我们设计一个类,不需要创建此类的实例时候,就可以考虑将其设置为抽象的,由其子类实现这个类的抽象方法以后,就行实例化

  2. abstract 修饰方法:抽象方法

    • 格式:没有方法体,包括{}.如:public abstract void eat();
    • 抽象方法只保留方法的功能,而具体的执行,交给继承抽象类的子类,由子类重写此抽象方法。
    • 若子类继承抽象类,并重写了所有的抽象方法,则此类是一个”实体类”,即可以实例化
    • 若子类继承抽象类,没有重写所有的抽象方法,意味着此类中仍有抽象方法,则此类必须声明为抽象的!

abstract的应用:模板方法设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//模板方法设计模式
public class TestTemplate {
public static void main(String[] args) {
new SubTemplate().spendTime();
}
}

abstract class Template {

public abstract void code();

public void spendTime() {
long start = System.currentTimeMillis();

this.code();

long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
}

class SubTemplate extends Template {

public void code() {
boolean flag = false;
for(int i = 2;i <= 10000;i++){
for(int j = 2;j <= Math.sqrt(i);j++){
if(i % j == 0){
flag = true;
break;
}
}
if(!flag){
System.out.println(i);
}
flag = false;
}
}
}

接口 interface

使用说明

接口(interface)是与类并行的一个概念

interface 的要点:

  1. 接口可以看做是一个特殊的抽象类。是常量与抽象方法的一个集合,不能包含变量、一般的方法。
  2. 接口是没有构造器的。
  3. 接口定义的就是一种功能。此功能可以被类所实现(implements)。
    比如:class CC extends DD implements AA
  4. 实现接口的类,必须要重写其中的所有的抽象方法,方可实例化。若没有重写所有的抽象方法,则此类仍为一个抽象类
  5. 类可以实现多个接口。—-java 中的类的继承是单继承的
  6. 接口与接口之间也是继承的关系,而且可以实现多继承
  7. 接口与具体的实现类之间也存在多态性
  8. 面向接口编程的思想

5, 6描述的是java中的继承的特点。

interface应用一:工厂方法的设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//接口的应用:工厂方法的设计模式
public class TestFactoryMethod {
public static void main(String[] args) {
IWorkFactory i = new StudentWorkFactory();
i.getWork().doWork();

IWorkFactory i1 = new TeacherWorkFactory();
i1.getWork().doWork();
}
}

interface IWorkFactory{
Work getWork();
}

class StudentWorkFactory implements IWorkFactory{

@Override
public Work getWork() {
return new StudentWork();
}
}
class TeacherWorkFactory implements IWorkFactory{

@Override
public Work getWork() {
return new TeacherWork();
}
}

interface Work{
void doWork();
}

class StudentWork implements Work{

@Override
public void doWork() {
System.out.println("学生写作业");
}
}
class TeacherWork implements Work{

@Override
public void doWork() {
System.out.println("老师批改作业");
}
}

interface应用二:代理模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//接口的应用:代理模式(静态代理)
public class TestProxy {
public static void main(String[] args) {
Object obj = new ProxyObject();
obj.action();
}
}

interface Object{
void action();
}
//代理类
class ProxyObject implements Object{
Object obj;

public ProxyObject(){
System.out.println("代理类创建成功");
obj = new ObjctImpl();
}

public void action(){
System.out.println("代理类开始执行");
obj.action();
System.out.println("代理类执行结束");
}
}
//被代理类
class ObjctImpl implements Object{

@Override
public void action() {
System.out.println("=====被代理类开始执行======");
System.out.println("=====具体的操作======");
System.out.println("=====被代理类执行完毕======");
}
}

内部类

类的第5个成员:内部类

  1. 相当于说,我们可以在类的内部再定义类。外面的类:外部类。里面定义的类:内部类
  2. 内部类的分类:成员内部类(声明在类内部且方法外的) vs 局部内部类(声明在类的方法里)
  3. 成员内部类:
    3.1是外部类的一个成员:①可以有修饰符(4个)②static final ③可以调用外部类的属性、方法
    3.2具体类的特点:①abstract ②还可以在其内部定义属性、方法、构造器
  4. 局部内部类:
  5. 关于内部类,大家掌握三点:
    ①如何创建成员内部类的对象(如:创建Bird类和Dog类的对象)
    ②如何区分调用外部类、内部类的变量(尤其是变量重名时)
    ③局部内部类的使用 (见TestInnerClass1.java)
坚持原创技术分享,您的支持将鼓励我继续创作!