5-JavaSE之面向对象编程-类与对象(上)

本节目标:

  1. 面向对象编程简介
  2. 类与对象的定义与使用
  3. private实现封装处理&构造方法(匿名对象)
  4. this关键字
  5. static关键字

1.面向对象编程简介

面向对象的三大特征:(面试经典考题)
1>面向对象的三大特征:

  • 封装性:内部操作对外部而言不可见(保护性)
  • 继承性:现有类不用重复编写代码而已对原有类进行扩充)(可重用)
  • 多态性:一个类实例的相同方法在不同情形有不同表现形式)。(如:方法重载)
    多态机制使具有不同内部结构的对象可以共享相同的外部接口。(利用多态可以得到良好的设计)

2>名词扩展:
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
面向对象最大的特征:可以进行生活的抽象

2.类与对象的定义与使用

2.1类与对象的概念

  • 类:指共性的概念
  • 对象:指的是一个具体的、可以使用的事物。

两者的关系:先产生类(类是生产对象的蓝图),而后才可以产生对象。对象的所有属性与行为,一定在类中进行了完整的定义。

类中的组成

  1. 方法(操作的行为)
  2. 属性(变量,描述每个对象的具体特点)

2.2类与对象的定义与使用
定义一个类:(此时的方法不再由主类直接调用,而需要由对象调用。)

class 类名称 {
	属性1;
	属性2;
	属性n...;
	方法1(){}
	方法2(){}
	方法n(){}...
}

范例:Person类的定义

class Person{
	public String name;
	public int age;
	
	public Person(String name,int age){
		this.name = name ;
		this.age = age ;
	}
	
	public String getPersonInfo(){
		return "姓名:"+this.name+",年龄:"+this.age;
	}
}

生产对象的语法

类名称 对象名称 = new 类名称();

以Person类为例 我们可以如下产生一个Person类的实例(对象 - 即对象的实例化):

Person p1 = new Person();
Person p2 = new Person("Steven",25);

范例:通过对象调用实例变量与实例方法

Person p = new Person("Steven",25);
System.out.println(p.name);
System.out.println(p.getPersonInfo());

只要出现了关键字new,就开辟了内存

2.3对象内存分析
我们可以简单的将java中的内存区域分为栈内存和堆内存两块区域(实际Java内存区域的划分远比这个复杂)

  • 栈内存(虚拟机局部变量表):存放的是局部变量(各种基本数据类型、对象引用-对象名字)

  • 堆内存:保存对象
    new表示在堆上新分配空间

  • 垃圾空间:没有任何栈内存指向的堆内存空间。

对象(引用数据类型)必须在实例化后调用,否则会产生NullPointerException(运行时错误),编译时不会出错
"NullPointerException"在各位今后的开发生涯中会一直存在,只有引用类型(数组、类、接口)才会产生此类异常。以后出现此类异常,就根据出错位置查看引用类型变量是否初始化。

2.4引用传递分析
引用传递的本质:一块堆内存可以被多个栈内存所指向

Person per1 = new Person();
Person per2 = new Person();
per2 = per1 ;

当per2 = per1 ;执行后,内存会怎样呢?per2在堆上分配的空间变为垃圾空间。(所有的垃圾空间会不定期GC,GC会影响性能,所以开发之中一定要控制好对象的产生数量(无用的对象尽量少产生))

3.private实现封装处理&构造方法(匿名对象)

3.1 private实现封装处理
将属性、方法用private封装后表示,被封装的属性与方法只能在本类中使用,类外部不可见。
private不可以用于外部类的封装,但是可以用于内部类的封装嵌套

private String name;
private int age;

此时使用了private对属性进行了封装,要访问私有属性,按照java的设计原则必须提供以下两种方法:

  1. setter方法:主要用于进行属性内容的设置与修改
  2. getter方法:主要用于属性内容的取得

范例:扩展Person类的内容

class Person{
	private String name;
	private int age;
	
	public void setName(String n){
		name = n ;
	}
	
	public String getName(){
		return name;
	}
	
	public void setAge(int i){
		if (i>0&&i<=200) {
			age = i ;
			}else {
			age = 0 ;
		}
	}

	public int getAge(){
		return  age;
	}
	
	public void getPersonInfo(){
		System.out.println("姓名:"+name+",年龄:"+age);
	}
}

public class Test{
	public static void main(String[] args) {
		Person person = new Person();
		person.setName("张三");
		person.setAge(-200);
		person.getPersonInfo();
	}
}

private实现封装的最大特征在于:只允许本类访问,而不允许外部类访问。
类的设计原则:

  • 以后编写类时,类中的所有属性必须使用private封装。
  • 属性若要被外部访问,必须定义setter、getter方法。

3.2构造方法与匿名对象
1>对产生对象的方法进行分析:

①Person  ②per = ③new  ④Person();

①表示这个对象通过哪个类产生
②要指向的堆内存地址,即产生的对象
③开辟一块堆内存
④构造方法
总结出:所谓的构造方法就是使用关键字new实例化新对象时来进行调用的操作方法。
2> 构造方法的三大特征(类中属性初始化): eg:Person()

  • 方法名称必须与类名称相同
  • 构造方法没有返回值类型声明
  • 每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造,若在类中自定义了构造方法,则系统不再默认生成无参构造)

3>问题:构造方法无返回值,为什么没有void声明?
回答该问题前我们看看现在类中的组成:属性、构造方法、普通方法

  1. 属性是在对象开辟堆内存时开辟的空间
  2. 构造方法是在使用new后调用的
  3. 普通方法是在空间开辟了、构造方法执行之后可以多次调用的

因此,编译器是根据程序结构来区分普通方法与构造方法的,所以在构造方法前没有返回值类型声明。
4>若类中定义了构造方法,则默认的无参构造将不再生成。
范例:使用构造方法设置对象属性

class Person{
	private String name;
	private int age;
	
	public Person(String n,int i){
		name = n ;
		setAge(i);
	}
	
	public void setName(String n){
		name = n ;
	}

	public String getName(){
		return name;
	}
	
	public void setAge(int i){
		if (i>0&&i<=200) {
			age = i ;
			}
			else {
			age = 0 ;
		}
	}
	
	public int getAge(){
		return age;
	}

	public void getPersonInfo(){
		System.out.println("姓名:"+name+",年龄:"+age);
	}
}


public class Test{
	public static void main(String[] args) {
		Person person = new Person("张三",-200);
		person.getPersonInfo();
	}
}

5>构造方法重载:参数个数不同

public Person(){
	System.out.println("===无参构造===");
}

public Person(String n){
	name = n ;
	System.out.println("===有参构造===");
}

6>类定义顺序:
①定义属性->②定义构造方法->③定义普通方法
7>范例:匿名对象

new Person("张三",20).getPersonInfo();

由于匿名对象不会有任何的栈空间所指向,所以使用一次后就成为垃圾空间。(直接在堆内存上开辟空间)

4.this关键字

4.1this调用本类属性 (只要在类中方法访问类中属性,一定要加this关键字)
观察代码:

class Person{
	private String name;
	private int age;
	
	public Person(String name,int age){  //参数与类中属性同名时,类中属性无法被正确赋值。
		name = name ;
		age = age ;
	}

	public String getPersonInfo(){
		return "姓名:" + name + ",年龄:"+age;
	}
}

public class Test{
	public static void main(String[] args) {
		Person per = new Person("张三",20);
		System.out.println(per.getPersonInfo());
	}
}

所以,当参数与类中属性同名时,类中属性无法被正确赋值。此时我们加上this关键字便可以正确给对象属性赋值。

this.name = name ;
this.age = age ;

4.2this调用本类方法
this调用本类方法有以下两种情况:

  • 1.调用普通方法:this.方法名称(参数)
  • 2.调用构造方法:this(参数)

范例:this调用普通方法

class Person{
	private String name;
	private int age;
	
	public Person(String name,int age){
		this.name = name ;
		this.age = age ;
		this.print();//调用普通方法
	}
	
	public String getPersonInfo(){
		return "姓名:" + name + ",年龄:"+age;
	}
	
	public void print(){
		System.out.println("*****************");
	}
}

public class Test{
	public static void main(String[] args) {
		Person per = new Person("张三",20);
		System.out.println(per.getPersonInfo());
	}
}

虽然调用本类普通方法不需要加this也可以正常调用。但强烈建议加上,加上this的目的可以区分方法的定义来源(在继承中有用).

在Java中,支持构造方法的互相调用(this)

public Person(){
	System.out.println("********产生一个新的Person对象********");
}

public Person(String name){
	this();//调用本类无参构造(可以省略无参构造方法下的(输出)内容)
	this.name = name ;
}

public Person(String name,int age){
	this(name);//调用本类有参构造
	this.age = age ;
}

使用this调用构造方法时请注意:

  1. this调用构造方法的语句必须在构造方法首行
  2. 使用this调用构造方法时,请留有出口

4.3this调用本类对象
范例:this表示当前对象

class Person{
	public void print(){
		System.out.println("[PRINT]方法:"+this); //此处this
	}
}

public class Test{
	public static void main(String[] args) {
		Person p1 = new Person();
		System.out.println("[MAIN]方法:"+p1); //此处p1
		p1.print();
		System.out.println("=================");
		Person p2 = new Person();
		System.out.println("[MAIN]方法:"+p2); //此处p2
		p2.print();
	}
}

只要对象调用了本类中的方法,这个this就表示当前执行的对象

5.static关键字(重要)

5.1static属性(类属性 — 静态属性)
static属性称为类属性,保存在全局数据区中(方法区 - 所有对象共享区域),所有对象都可以进行该数据区的访问,通过类名调用,与对象实例化无关。
描述共享属性使用static属性(1%比例)
如:

class Person{
	static String Country = "中国"; //所有对象都可以进行该数据区的访问
	String name;
	int age;
	...
}

1.访问static属性(类属性)应使用类名称.属性名
2.所有的非static属性(实例变量)必须在对象实例化后使用,而static属性(类属性)不受对象实例化控制
5.2static方法(类方法)
通过类名调用,与对象实例化无关。常见于工具类方法

public static void setCountry(String c){
	country = c ;
}

局部变量(写在方法中的变量)不能用static修饰

关于static方法有以下两点说明:

  1. 所有的static方法不允许调用非static定义的属性或方法
  2. 所有的非static方法允许访问static方法或属性

总结:使用static定义方法只有一个目的:某些方法不希望受到类的控制,即可以在没有实例化对象的时候执行(广泛存在于工具类中)
结论:static与private均不能加在外部类之上,内部类可以(静态内部类)

猜你喜欢

转载自blog.csdn.net/qq_39378530/article/details/83186668