类与对象详讲(轻松易懂,就是文章比较长)

一.了解面向对象的编程思想.

1.1 面向对象

a.Java是一种纯面向对象语言(Object Oriented Program).
b.面向对象思想是人类最自然的一种思考方式,他将所有预处理的问题抽象为对象,同时了解这些对象具有哪种相应的属性以及展示这些对象的行为,以解决这些对象面临的一些实际问题.
c.面向对象设计实质上就是对现实世界中的对象进行建模操作.
d.面向对象程序设计有以下三个特点
封装性,继承性,多态性,如果强调的是四个特点,就再加一个抽象性.

1.2 对象

对象是事物存在的实体.现实世界中,随处可见的就是对象,如人,动物,电脑,桌子等等.
我们通常会把对象划分为两个部分,即静态部分动态部分.
静态部分(属性):就是不能动的部分,这个部分称之为属性,比如人的姓名,性别,年龄等等.
动态部分(行为):具有这些属性的人会执行一些动作,如哭,笑,唱,跳,rap,篮球等等,这些是这个人所具有的行为,这个行为就是动态部分.我们通过探讨对象的属性和观察对象的行为来了解对象.下面给大家举一个例子:
例如:有一个人要从Ta家门口跑步去公司上班.
a.我们先抽象出对象,这里的对象就是人.
b.识别这个对象的属性:高低,胖瘦,性别等,对象具有的属性都是静态属性.
c.接着来识别对象的行为:跑步,跑累了休息或者慢走等.
d.识别出这个对象的属性和行为后,这个对象就被定义完成了.

二.类的定义和使用

2.1.简单认识类

a.类就是同一类事物的统称.如家禽,鸟类,人类等.
b.类是对一个实体对象进行描述的,主要描述该实体对象具有哪些属性,哪些功能.
c.类是封装对象的属性和行为的载体.
d.类中对象的行为是以方法的形式定义的,对象的属性是以成员变量的形式定义的,所以类包括对象的属性和方法.

2.2.类的定义格式

在Java中创建类需要使用class关键字.具体语法如下

/*
	class为定义类的关键字,ClassName是类的名字,{}中为类的主体
	
	类中包含的内容称为类的成员。
	
	属性主要是用来描述类的,称之为类的成员属性或者类成员变量。
	
	方法主要说明类具有哪些功能,称为类的成员方法。
*/
class ClassName{
    
    
	field;				//字段(属性)或者成员变量
	method;				//行为或者成员方法
}

我们举一个笔记本电脑的例子:

/*
	 注意事项:
	 	1.类名注意采用大驼峰定义
	 	2.此处写的方法不带有static关键字
*/
class Laptop{
    
    
	 String brand; 				// 品牌
 	 String type; 				// 型号
 	 double weight; 			// 重量
	 double lenght; 			// 长
 	 double weidth; 			// 宽
	 double height; 			// 高
 	 String color;		   	    // 颜色
 	 public void Starting(){
    
    		
		System.out.println("开机");
	}
	 public void EnterGame(){
    
    		
		System.out.println("进入游戏");
	}
	 public void ShutDown(){
    
    
		System.out.println("关机");
	}
}

2.3 类的使用会在下面实例化中给出

三.类的实例化

3.1.什么是实例化

定义一个类,相当于定义了一个新的类型,与int,double相似,只不过int,double是Java语言自带的内置类型,而类是用户自定义了一个新的类型.比如上方的笔记本电脑类.
用类类型创建对象的过程,称为类的实例化,在Java中采用new关键字,配合类名来实例化对象.

public class Test{
    
    
	public static void main(String[]args){
    
    
		//通过new实例化对象,使用.来访问对象中的属性和方法
		//一个类也可以创建多个实例
		Laptop lt=new Laptop();
		lt.brand="华为";
		lt.type="1008611";
		lt.color="white";
		lt.Starting();
		lt.EnterGame();
		lt.ShouDown();
	}
}

3.2.类和对象的说明

a. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
b. 类是一种自定义的类型,可以用来定义变量,但是在java中用类定义出来的变量我们成为对象.
c. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量.
d. 做个比方.类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间.

四.this关键字

4.1 为什么要用this引用?

看this之前先看一个代码:

public class Student{
    
    
	private String name;
	private String gender;
	private int age;
	//a.形参名不小心与成员变量名相同,函数体到底给谁赋值?
	public void setInfor(String name,String gender,int age){
    
    
		name=name;
		gender=gender;
		age=age;
	}
	public void printInfor(){
    
    
		System.out.println("name 是:"+name+",gender是:"+gender+",age是:"+age);
	}
	public static void main(String[] args){
    
    
		Student s1=new Student();
		Student s2=new Student();
		/*
			b.两个对象都在调用setInfor和printInfor方法,
				但是两个方法中没有任何有关对象的说明,
				setInfor和printInfor方法如何知道打印的是哪个对象的数据呢?
		*/
		s1.setInfor("wang","男",21);
		s2.setInfor("zhang","女",20);

		s1.printInfor();
		s2.printInfor();
	}
}

这个时候就需要使用this引用了.

4.2 什么是this关键字.

其实,java编译器给每个“成员方法“增加了一个隐藏的引用类型参数,该引用参数指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

public class Student{
    
    
	private String name;
	private String gender;
	private int age;
	public void setInfor(String name,String gender,int age){
    
    
		/*
			this.name指的就是Student类中的name成员变量方法.
			this.name=name语句中第二个name则指的是形参name
			实际上setInfor()方法实现的功能就是将name的值赋值给成员变量name.
		*/
		this.name=name;
		this.gender=gender;
		this.age=age;
	}
	public void printInfor(){
    
    
		System.out.println("name 是:"+this.name+",gender是:"+this.gender+",age是:"+this.age);
	}
}

this引用是编译器自动添加的,用户在实现代码时一般不需要显式给出.
注意:this引用的是调用成员方法的对象.

public static void main(String[] args) {
    
    
 	Student s = new Student();
 	s.setInfor("wang","男",21);
 	s.printDate();
}

4.3 this引用的特性.

a. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
b. this只能在"成员方法"中使用
c. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象,具有final属性
d. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法
对象的引用传递给该成员方法,this负责来接收.

五.对象的构造即初始化

5.1.初始化对象

5.1.1 局部变量

局部变量的有效范围是从该变量的声明开始到该变量的结束为止

public static void main(String[] args){
    
    
	int a;
	//会编译失败,因为局部变量未初始化.
	System.out.println(a);
}

5.1.2 对象

public static void main(String[] args){
    
    
	Laptop lt=new Laptop();
	lt.Starting();
	lt.EnterGame();
	lt.ShouDown();
}

5.2.构造方法

5.2.1 概念

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

5.2.2 语法

/*
	注意:在定义构造方法时,构造方法没有返回值,但这与普通没有返回值的方法不同,
		普通的方法使用public void method(){}这种形式进行定义,
		但是构造方法不需要void关键字进行修饰
*/
//public是修饰符,book是本类的类名
public class book(){
    
    
	//不需要void进行修饰
	public book(){
    
    
	
	//此处构造方法体
	
	}
}

5.2.3 特性总结

a. 名字必须与类名相同(5.2.2)
b. 没有返回值类型,设置为void也不行(5.2.2)
c. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)

public class Date(){
    
    
	int year;
	int month;
	int day;
	public Date(){
    
    
		System.out.println("我是构造方法");
	}
	public static void main(String[] args){
    
    
	    //每当类实例化一个对象时,类都会自动调用构造方法.
		Date d1=new Date();
		Date d2=new Date();
		/*
		 运行后打印的结果为:
		 我是构造方法
		 我是构造方法
		*/
	}
}

d. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)

//这个类中定义了构造方法,所以编译器不会自动生成不带参数的构造方法
//方法名字相同,参数列表不同,因此也构成了重载
public class Date(){
    
    
	int year;
	int month;
	int day;
	//无参构造方法
	public Date(){
    
    
		this.year=2021;
		this.month=9;
		this.day=24;
	}
	//带有三个参数的构造方法
	public Date(int year, int month, int day) {
    
    
		 this.year = year;
		 this.month = month;
		 this.day = day;
	 }
	 //打印日期的方法
	 public void printDate(){
    
    
		 System.out.println(year + "-" + month + "-" + day);
	 }
	 
	 public static void main(String[] args) {
    
    
 		  Date d = new Date();
		  d.printDate();
	 }
}

e.如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
注意: 如果在类中定义的构造方法都不是无参的构造方法,那么编译器也不会为类设置一个默认的无参构造方法,当试图用无参构造方法实例化一个对象时,编译器会报错.所以只有在类中没有定义任何的构造方法时,编译器才会自动创建一个不带参数的构造方法.

//这个类中没有定义构造方法,那么编译器会自动生成一个不带参数的默认构造方法
public class Date(){
    
    
	int year;
	int month;
	int day;
	
	public void printDate(){
    
    
		 System.out.println(year + "-" + month + "-" + day);
	 }
	 
	 public static void main(String[] args) {
    
    
 		  Date d = new Date();
		  d.printDate();
	 }

六.封装

6.1 封装的概念

封装是面向对象编程的核心思想.
将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现的细节,这就是封装的思想.
举一个简单的例子:用户使用计算机时,只需要用鼠标或者键盘就可以实现一些功能,不需要知道计算机内部是怎样工作的.
使用类实现封装特性如下图所示:
封装特性示意图

6.2 访问限定符

权限修饰符详讲

6.3 封装扩展之包

会独自出一篇博客去介绍的.

七.static关键字

7.1初始static关键字

在Java中被static修饰的成员称之为静态成员,也可以称之为类成员,其不属于某个具体的对象,是所有对象所共享的.
比如学生类:

public class Student{
    
    
/*
	现在要表示一个班的学生,学生的名字,性别,年龄一般都不相同,
	  但是上课的教室是一样的,要让所有学生共享,所以使用static
	  来进行修饰.
*/
	String name;
	String gender;
	int age;
	//用static来修饰教室,教室是这个班学生所共享的.
	static String classRoom;
}

7.2static修饰成员变量

static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
静态成员变量特性
a. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
b. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
c. JDK7及以前,HotSpot(Java虚拟机)中存储在方法区,JDK8及之后,类变量存储在Java堆中
d. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)

//再看学生类
public class Student{
    
    
	public String name;
	public String gender;
	public int age;
	public double score;
	public static String classRoom="335";
	//有参构造方法
	public Student(String name,String gender,int age,double score){
    
    
		this.name=name;
		this.gender=gender;
		this.age=age;
		this.score=score;
	}
	public static void main(String[] args){
    
    
		//静态成员变量可以直接通过类名访问
		System.out.ptintln(Student.classRoom);
		Student s1=new Student("wang","男",21,89.5);
		Student s1=new Student("zhang","男",19,76.5);
		Student s1=new Student("liu","女",22,80.5);
		//也可以通过对象访问:但是classRoom是三个对象所共享的.
		System.out.println(s1.classRoom);
 		System.out.println(s2.classRoom);
 		System.out.println(s3.classRoom)
	}
}
```再来看一个例子.
```java
public class Student{
    
    
	//在这里就写一个教室属性,说明问题就行
	private static String classRoom="335";
}
public class TestStudent{
    
    
	public static void main(String[] args){
    
    
		//这里会编译失败,因为classRoom在Student类中受private访问控制.
		//System.out.println(Student.classRoom);
	}
}

注意:在Java中规定不能将方法体内的局部变量定义为static的.

//编译错误.
public class example{
    
    
	public void method(){
    
    
		static int i=0;
	}
}

7.3 static修饰成员方法

Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的。
再看Student类.

public class StaticTest{
    
    
	static double PI=3.14;
	static int id;
	public static void method1(){
    
    
		System.out.println("我是静态方法method1");
	}
	public void method2(){
    
    
		System.out.println(StaticTest.PI);//调用静态常量
		System.out.println(StaticTest.id);//调用静态变量
		StaticTest.method1();//调用静态方法
	}
	//在类中定义一个静态方法
	public static StaticTest method3(){
    
    
		//调用非静态方法
		method2();
		//在return语句中使用this关键字
		return this;
	}
}
编译后会发生错误,这是因为method3()方法为一个静态方法,而在其方法体中调用了非静态方法和this关键字.Java中对静态语言有两点规定.
a.在静态方法中不能使用this关键字.
b.在静态方法中不能直接调用非静态方法

静态方法特性:
a.不属于某个具体的对象,是类方法.
b.可以通过对象调用,也可以通过 类名.静态方法名(…)的方式调用,
比较推荐后者的调用方式.
c.静态方法没有隐藏的this引用参数,因此不能在静态方法中访问任何非静态成员变量.
d. 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用.

7.4 static成员变量初始化

注意:注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性.
静态成员初始化分为两种:就地初始化静态代码块初始化.

7.4.1 静态初始化

指的是在定义的时候直接给出初值.

public class Student{
    
    
	public String name="wang";
	public String gender="男";
	public int age=21;
	public double score=100.0;
	public static String classRoom="335";

7.4.2 静态代码块初始化.

在下面的代码块模块有讲解.

八.代码块

8.1代码块的概念以及分类

使用 { } 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
a.普通代码块
b.构造代码块
c.静态代码块
d.同步代码块(暂时不谈,会在多线程阶段进行介绍)

8.2 普通代码块

定义在方法中的代码块,并不常用

public class Test{
    
    
	public static void main(String[] arg){
    
    
		//直接使用{}进行定义
		{
    
    
			int x=10;
			System.out.println("x1="+x);
		}
		{
    
    
			int x=100;
			System.out.println("x2="+x);
		}
		/*
			执行结果:
			x1=10
			x2=100
		*/
	}
}

8.3 构造代码块

定义在类中的代码块(不加修饰符),别名:实例代码块
构造代码块一般用于初始化实例成员变量.

public class Student{
    
    
	//实例成员变量
	private String name;				//学生姓名
	private String gender;				//学生性别
	private int age;					//学生年龄
	private double score;				//学生成绩
	public Student{
    
    
		System.out.println("我是构造方法!");
	}
	//实例代码块
	{
    
    
		this.name="wang";
		this.gender="Man";
		this.age=21;
		this.score=100.0;
		System.out.println("我是实例代码块!");
	}
	public void show(){
    
    
 		System.out.println("name: "+name+" age: "+age+" gender: "+gender);
    }
    public class TestStudent {
    
    
	    public static void main(String[] args) {
    
    
	    //在创建对象时,实例代码块会执行,每创建一个对象执行一次
	    Student s1 = new Student();
	    Student s2 = new Student();
		}
	}
}
运行结果:
我是实例代码块!
我是构造方法!
我是实例代码块! 
我是构造方法!

注意:由输出结果可以看见,实例代码块要优先于构造方法执行,其实并不是实例代码块先执行,原因是:先将实例代码块拷贝到构造方法的第一行,在创建对象时,先调用构造方法,而构造方法第一行是代码块,所以代码块中的内容先输出出来,再往下执行,也就是我们所看到的那样,代码块的内容在前面.

8.4 静态代码块.

使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。

public class Student{
    
    
	//实例成员变量
	private String name;				//学生姓名
	private String gender;				//学生性别
	private int age;					//学生年龄
	private double score;				//学生成绩
	static int count=0;
	public Student{
    
    
		System.out.println("我是构造方法!");
	}
	//静态代码块----用来初始化静态成员变量的
	//在类加载(在后面的JVM中会进行介绍)时只执行一次.在创建对象之前调用的.
	static{
    
    
		System.out.println(count);
		count=1;
		System.out.println(count);
		System.out.println("我是静态代码块!");
	}
	public class TestStudent {
    
    
	    public static void main(String[] args) {
    
    
	    //在类加载时,不管创建多少个对象,静态代码块只执行一次.	
	    Student s1 = new Student();
	    Student s2 = new Student();
		}
	}
}
输出结果:
0
1
我是静态代码块!

九.内部类

9.1 概念介绍

在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,
前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

//OutClass是外部类,InnerClass是内部类
public class OutClass{
    
    
	class InnerClass{
    
    
	
	}
}

注意事项:

1.定义在class类名{
    
    }花括号外面的,即使在同一包中,都不能称为内部类
//a和b是两个独立的类,两者之间没有关系.
public class A{
    
    

}
class B{
    
    

}
2.内部类和外部类共用一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件

9.2 内部类的分类

根据内部类定义的位置不同,一般可以分为以下几种形式:

9.2.1.成员内部类

在外部类中,内部类定义位置与外部类成员所处的位置相同,因此称为成员内部类。又可以分为a,b两种类.
a.普通内部类:未被static修饰的成员内部类

public class OutClass {
    
    
	 private int a;
	 static int b;
	 int c;
	 public void methodA(){
    
    
		 a = 10;
		 System.out.println(a);
	 }
	 public static void methodB(){
    
    
 		 System.out.println(b);
 }
 // 成员内部类:未被static修饰
	 class InnerClass{
    
    
 		 int c;
 		 public void methodInner(){
    
    
 			// 在内部类中可以直接访问外部类中:任意访问限定符修饰的成员
			 a =100;
			 b =200;
 			methodA();
 			methodB();
 			// 如果外部类和内部类中具有相同名称成员时,优先访问的是内部类自己的
			 c = 300;
			 System.out.println(c);			//300
			 
 			// 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
			 OutClass.this.c = 400;
			 System.out.println(OutClass.this.c);	//400
		 }
	 }
   	public static void main(String[] args) {
    
    
		 // 普通内部类:对象创建 以及 成员访问
		 OutClass outClass = new OutClass();
		 System.out.println(outClass.a);
 		 System.out.println(OutClass.b);
 		 System.out.println(outClass.c);
 		 outClass.methodA();
 		 outClass.methodB();
		 System.out.println("==========================");
		 /* 
		 要访问普通内部类中成员,必须要创建普通内部类的对象
 		 而普通内部类定义与外部类成员定义位置相同,
 		 	因此创建普通内部类对象时必须借助外部类
		 */ 
		 // 创建内部类对象
		 OutClass.InnerClass ic1 = new OutClass().new InnerClass();
		 /*
		 上述语法比较怪异,也可以先将外部类对象先创建出来,
		 		然后再创建内部类对象
		 */
		 OutClass oc=new OutClass();
		 InnerClass ic2 = oc.new InnerClass();
 		 ic2.methodInner();
	 }
}

b.静态内部类:被static修饰的成员内部类

	 static class InnerClass{
    
    
 		public void methodInner(){
    
    
 		 // 在内部类中只能访问外部类的静态成员
		 // a = 100;  编译失败,在静态内部类中不能直接访问外部类中的实例变量
		 b =200;
		 // methodA();  编译失败,因为methodA()不是静态成员方法
         methodB();
	 }
	 public static void main(String[] args) {
    
    
		 // 静态内部类对象创建 & 成员访问
		 //不需要借助外部类对象来创建了
 		InnerClass ic = new InnerClass();
 		ic.methodInner();
	 }

9.2.2.局部内部类

定义在外部类的方法体或者{ }中,该种内部类只能在其定义的位置使用,一般使用的非常少,此处简单了解下就行。

public class ScopedInnerClass{
    
    
	public void method(){
    
    
		int a=10;
		System.out.println(a);
		//局部内部类---该内部类只能在该方法中使用,其他位置使用不了
		//不能被访问修饰符限制----public
		//不能在局部内部类中定义静态成员
		class InnerClass{
    
    
			int b;
			//static int c;
			//static void fun(){}
		}
		InnerClass ic=new InnerClass();
	}
	public static void main(String[] args){
    
    
		//编译失败:局部内部类只能在其定义的方法的内部使用
		//InnerClass ic=null;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_47278183/article/details/120327516