Java面向对象编程

第一章 类与对象

面向对象简介

面向过程指的是面对于一个问题的解决方案,更多情况下不会做出重用的设计。

面向对象主要设计形式为模块化设计,可以进行重用配置,更多情p况下考虑的是标准,然后根据标准进行拼装。

面向对象有三个主要特性:

封装性:内部的操作对外部不可见,当内部的操作都不可直接使用的时候才是安全的;

继承性:在已有结构的基础上继续进行功能的扩充;

多态性:在继承性的基础上扩充而来的概念,指的是类型的转换处理。

面向对象程序开发的步骤:

        OOA:面向对象分析;OOD:面向对象设计;OOP:面向对象编程。

类与对象简介

类是对某一类事物共性的抽象概念。

对象描述的是一个具体的产物。

类是一个模板,而对象是类的实例,所以先有类才有对象。(类比为船的图纸(类)与船(对象),根据图纸可以造很多船)

类的组成:

        成员属性(Field):简化称为”属性“,其对象的特征(人的姓名、人的年龄...),属性是指描述对象的一组数据,表现为对象的一些变量。

        操作方法(Method):表示对象的行为或所作的工作。

类与对象的定义及使用

Java中类是一个独立的结构体,所以需要用class来定义

public class Student {
    // 类的属性:成员变量
    String name;
    int age;
    String like;

    // 成员方法(实例方法)
    public void show(){
        System.out.println("我叫"+name+",今年"+age+",我的爱好"+like);
    }
    // main方法
    public static void main(String[] args) {
        Student stu = new Student(); //创建对象,通过类来创建对象 new 类名()
        stu.name = "张三"; // 调用成员变量赋值:对象名.属性名
        stu.age = 20;
        stu.like = "干饭";
        stu.show(); // 调用成员方法
    }
}

语法:

        产生对象:

        一步完成: 声明并实例化对象:类名称 对象名称 = new 类名称();

        分步完成: 声明对象:类名称 对象名称 = null;

                           实例化对象:对象名称 = new 类名称();

        调用: 类中的属性:对象名称.成员属性

                    类中的方法:对象名称.方法名称()

如果程序没有进行对象属性内容的设置,则数据内容为其对应数据类型的默认值。

对象内存分析

Java中类属于引用数据类型,困难之处在于要进行内存的管理。所以对内存管理进行简单分析。

最常用的内存空间:

堆内存:保存对象的具体信息,在程序中堆内存空间的开辟是通过new完成的;

栈内存:保存单块堆内存的地址。即:通过通过地址找到堆内存,而后找到对象内容。但是为了分析简化起见,可以简单的理解为:对象名称保存在了栈内存之中。

直接声明并实例化对象的内存分析:

class Person { // 定义一个类
	String name; // 人的姓名
	int age; // 人的年龄
	public void tell() {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
}
public class JavaDemo { 
    public static void main(String[] args) { 
        Person per = new Person(); // 声明并实例化对象 
        per.name = "张三"; 
        per.age = 18; 
        per.tell(); // 进行方法的调用 
    } 
}  

 分步骤声明再实例化对象的内存分析

public class JavaDemo {
	public static void main(String[] args) {
		Person per = null; // 声明对象
		per = new Person(); // 实例化对象
		per.name = "张三";
		per.age = 18;
		per.tell(); // 进行方法的调用
	}
}

所有调用类的属性和方法在实例化对象完成后才能执行,调用只声明但没有实例化的对象

public class JavaDemo {
	public static void main(String[] args) {
		Person per = null; // 声明对象
		per.name = "张三";
		per.age = 18;
		per.tell(); // 进行方法的调用
	}
}

上述代码会产生“java.lang.NullPointerException”的空指向异常,因为此时并没有在堆内存中开辟空间,这种情况只发生于引用数据类型。

对象引用分析

由于类属于引用数据类型,因此就牵扯到内存的引用传递。

引用传递:指同一块堆内存被不同的栈内存所指向。

在主方法中使用引用传递:

public class JavaDemo {
	public static void main(String[] args) {
		Person per1 = new Person(); // 声明并实例化对象
		per1.name = "张三";
		per1.age = 18;
		Person per2 = per1; // 引用传递
		per2.age = 80;
		per1.tell(); // 进行方法的调用
	}
}

利用方法实现引用传递:

与之前的差别最大的地方在于,此时的程序是将Person类的实例化对象(内存地址、属性的参数)传递到了change()方法中,由于传递的是一个Person对象类型,那么change()接收的也是Person类型。  

public class JavaDemo {
	public static void main(String[] args) {
		Person per = new Person(); // 声明并实例化对象
		per.name = "张三";
		per.age = 18;
		change(per); // 等价于:Person temp = per;
		per.tell(); // 进行方法的调用
	}
	public static void change(Person temp) {
		temp.age = 80;
	}
}

 引用传递可以发生在方法上,要观察方法里面传的的参数类型,同时也要观察方法的执行过程。

引用与垃圾产生分析

引用传递的本质:一场堆内存的调戏游戏。但引用传递,引用不当会产生垃圾。对垃圾产生原因进行简单分析。

public class JavaDemo {
	public static void main(String[] args) {
		Person per1 = new Person(); // 声明并实例化对象
		Person per2 = new Person();
		per1.name = "张三";
		per1.age = 18;
		per2.name = "李四";
		per2.age = 19;
		per2 = per1; // 引用传递
		per2.age = 80;
		per1.tell(); // 进行方法的调用
	}
}

 垃圾空间:没有任何栈内存所指向的堆内存空间,所有的垃圾都将被GC(Garbage Collector:垃圾收集器)不定期进行回收,并且释放无用空间,但如果垃圾过多,一定将影响到GC的处理性能,从而降低整体的程序性能。

一个栈内存只能够保存一个堆内存的地址数据,如果发生更改,则之前的地址数据将从此栈内存中彻底消失。

第二章 深入分析类与对象

成员属性封装

类的组成就是属性与方法,一般而言方法都是对外提供服务的,所以是不会进行封装处理的;而属性需要较高的安全性,所以就需要封装性对属性进行保护。

对属性进行封装:使用private关键字。

class Person { // 定义一个类
	private String name; // 人的姓名
	private int age; // 人的年龄
	public void tell() {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
}

属性一旦封装后,外部将不可以直接进行访问。

【setter、getter】设置或取得属性使用setXxx()、getXxx()方法。

设置属性方法:public void setName(String name) {};

获取属性方法:public String getName() {};

class Person { // 定义一个类
	private String name; // 人的姓名
	private int age; // 人的年龄
	public void tell() {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
	public String getName() {
        return name;
    }
    public void setName(String newName) {
        name = newName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int newAge) {
        age = newAge;
    }
}
public class JavaDemo {
	public static void main(String[] args) {
		Person per = new Person(); // 声明并实例化对象
		per.setName("张三"); // 在类外部通过方法修改私有属性
		per.setAge(18);
		per.tell(); // 进行方法的调用
	}
}

在定义类时,属性都应该使用private封装(98%),并提供setter、getter方法。

构造方法与匿名对象

现在的程序在使用类的时候一般都按照了如下的步骤进行:

声明并实例化对象,这个时候实例化对象中的属性并没有任何的的数据存在,都是其对应数据类型的默认值。

需要通过一系列的setter()方法设置属性值

public class JavaDemo{ // 主类
​	public static void main(String args[]){
​		// 1、对象初始化准备
​		Person per = new Person(); // 声明并实例化对象
​		per.setName("张三");
​		pei.setAge(-18); // 在类外部修改属性
​		// 2、对象的使用
​		per.tell(); // 进行方法的调用
​	}
}

假设现在类中的属性有很多个,按上述方法,需要调用多次setter方法进行设置,过于麻烦,所有提供构造方法,实现实例化对象中的属性初始化处理。

构造方法作用:实现实例化对象中的属性初始化处理。 使用:通过new关键字进行实现(因为实例化对象就是通过new关键字实现的)。

定义要求:

        构造方法名称必须与类名称一致;

        构造方法不允许设置返回值类型,即:没有返回值定义;

        构造方法时在使用new关键字实例化对象时自动调用的。         

class Person { // 定义一个类
	private String name; // 人的姓名
	private int age; // 人的年龄
	public Person(String n, int a) { // 定义有参构造
        name = n; // 为类中的属性赋值(初始化)
        age = a; // 为类中的属性赋值(初始化)
    }
	public void tell() {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
}
public class JavaDemo { // 主类
	public static void main(String[] args) {
		// 1、对象初始化准备
		Person per = new Person("张三", 18); // 声明并实例化对象
		// 2、对象的使用
		per.tell(); // 进行方法的调用
	}
}

实例化对象例子对比:

        之前:①Person ②per= ③new ④Person()

        当前:①Person ②per= ③new ④Person(“张三”, 18)

解析:

        ①Person:定义对象的所属类型,类型决定了可以调用的方法;

        ②per=:实例化对象的名称,所有的操作通过对象来进行访问;

        ③new:开辟一块新的堆内存空间;

        ④Person():调用无参构造; ④Person(“张三”, 18):调用有参构造。

在Java程序里面考虑到程序结构的完整性,所以所有的类都会提供有构造方法,如果你的类中没有定义的构造方法,那么程序会默认提供无参的构造方法,这个是在程序编译时自动创建的;

如果你的类中有定义构造方法,那么程序则不会自动提供无参的构造方法。所以一个类至少存在有一个构造方法,且永恒存在。

疑问:为什么构造方法上不允许设置返回值类型?

程序编译器是根据代码结构来进行编译处理的,执行时也是根据代码结构来处理的。

因此如果设置了返回值类型,那么构造方法的结构与普通方法的结构完全相同,这样编译器会认为此方法时一个普通方法。

普通方法与构造方法最大的区别:构造方法是在类对象实例化时调用的,而普通方法是在类对象实例化产生之后才可以调用的。

构造方法本身就是一个方法,其具有重载的特点,而构造方法重载的时候只需要考虑参数的类型及个数即可。

进行多个构造方法定义的时候可以有定义的顺序,如按照参数的个数降序或升序进行。

构造方法可以进行数据的设置,而setter也可以进行数据的设置。构造方法是在对象实例化的时候为属性设置初始化内容,而setter还拥有修改数据的内容。

匿名对象:直接实例化对象来进行类的操作(没有声明对象,所以对象是没有名字的)。

public class JavaDemo { // 主类
	public static void main(String[] args) {
		new Person("张三", 10).tell(); // 通过匿名对象直接进行方法的调用
	}
}

通过匿名对象调用方法,由于此对象没有任何的引用名称,因此该对象在使用一次之后就成为了垃圾,而所有的垃圾都将被GC进行回收与释放。

通过以下程序,进行简短的内存分析。

class Message{
	private String title;
	public Message(String t) {
		title = t;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String t) {
		title = t;
	}
}
class Person{
	private String name;
	private int age;
	public Person(Message msg,int a ) {
		name = msg.getTitle();
		age = a;
	}
	public Message getInfo(){
		return new Message(name + ":" + age)
	}
	public void tell() {
		System.out.println("姓名" + name + "年龄" + age);
	}
}
public class No1PersonMessage {
	public static void main(String args[]) {
		Message msg = new Message("mldn");
		Person per = new Person(msg,20);
		msg = per.getInfo();
		System.out.println(msg.getTitle());
	}	
}

 只要是方法都可以传递任意的数据类型(基本数据类型、引用数据类型)。

this关键字

this可以实现以下三类 结构的描述:

        当前类中的属性:this.属性名;

        当前类中的方法:构造方法:this();普通方法:this.方法名();

        描述当前对象;

在Java程序中,“{}”是作为一个结构体的边界符,所以在程序里面当进行变量(参数 / 属性)使用时,都会以“{}”作为查找边界。按照就近取用的原则,此时的构造方法并没有能够访问类中的属性,所以为了明确标记类中的属性和参数的区别,往往会在属性前追加一个this,表示本类的属性。

只要是访问本类中的属性的时候,都要加this。

class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
        this.name = name;
        this.age = age
    }
	public void tell() {
		System.out.println("姓名:" + this.name + ",年龄:" + this.age);
	}
}

待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值