(一).面向对象的初步认知
1.1什么是面向对象?
Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人 们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。
1.2面向对象的过程
面向对象的过程其实有非常多种比如洗衣机洗衣服的过程,我们用洗衣机洗衣服我们只在意它的结果而并不在意过程,这时我们面向的对象就只有人,洗衣粉,衣服,洗衣机。
洗衣服的过程:人将衣服放进洗衣机,倒入洗衣粉,启动洗衣机,洗衣机完成洗衣的过程。
整个过程:主要是人,衣服,洗衣粉,洗衣机四个对象之间相互完成的,而我们并不关心它是如何进行洗衣服的过程和如何甩干的。,就如下图所示:
这个方法就是通过面向对象的方式来处理。
注意:面向对象和面向过程只是运用于专门的场景,而并非一种语言。
面向对象顾名思义就是:
1.找对象
2.创建对象
3.使用对象
(二).类定义和使用
2.1简单认识类
类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干 啥),描述完成后计算机就可以识别了。例如:
比如:洗衣机,它是一个品牌,在Java中可以将其看成是一个类别。
属性:产品品牌,型号,产品重量,外观尺寸,颜色...
功能:洗衣,烘干、定时....
2.2类的定义格式
Java中定义类需要用到class关键字,具体方式如下:
// 创建类 class ClassName{ field; // 字段(属性) 或者 成员变量 method; // 行为 或者 成员方法 }
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
我们还应注意的是一般一个Java文件中定义一个类,并且类名都采用大驼峰的形式。
我们可以将上面洗衣服的过程进行实例化:
public class WashMachine { public String brand; // 品牌 public String type; // 型号 public double weight; // 重量 public double length; // 长 public double width; // 宽 public double height; // 高 public String color; // 颜色 public void washClothes(){ // 洗衣服 System.out.println("洗衣功能"); } public void dryClothes(){ // 脱水 System.out.println("脱水功能"); } public void setTime(){ // 定时 System.out.println("定时功能"); } }
定义一个学生类:
public class Student { public String name; public int age; public String gender; public double score; public void DoClass(){} public void DoHomework(){} public void Exam(){} }
注意事项:
1. 一般一个文件当中只定义一个类
2. main方法所在的类一般要使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)
3. public修饰的类必须要和文件名相同
4. 不要轻易去修改public修饰的类的名称.。
(三).类的实例化
3.1什么是类的实例化?
类的实例化相当于先定义了一个类,就相当于在计算机中定义了一个新的类型,不过和我们平时使用的int,double等计算机语言自带类型不一样。用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。
例如:
图中就是一个简单的实例化的运用。
例如:
同时当我们定义时,
定义一个新的类型时它的变量如果我们没有人为定义,它自己会有一个默认值,并且遵循图中原则。
同时,还有一点需要注意:
局部变量在使用的时候要进行初始化。
注意事项:
1.new 关键字用于创建一个对象的实例.
2.使用 . 来访问对象中的属性和方法.
3.同一个类可以创建多个实例.
3.2类和对象的说明
1. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
2. 类是一种自定义的类型,可以用来定义变量.
3. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
4. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东 西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
(四).this引用
4.1为什么会有this引用
public class Date { public int year; public int month; public int day; public void setDay(int y, int m, int d){ year = y; month = m; day = d; } public void printDate(){ System.out.println(year + "/" + month + "/" + day); } public static void main(String[] args) { // 构造三个日期类型的对象 d1 d2 d3 Date d1 = new Date(); Date d2 = new Date(); Date d3 = new Date(); // 对d1,d2,d3的日期设置 d1.setDay(2020,9,15); d2.setDay(2020,9,16); d3.setDay(2020,9,17); // 打印日期中的内容 d1.printDate(); d2.printDate(); d3.printDate(); } }
例如我们首先看看图中这段代码:
以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打 印,代码整体逻辑非常简单,没有任何问题。 但是我们能明显的注意到的是如图:
1.它的形参名和成员变量名相同,
2. 三个对象都在调用setDate和printDate函数,但是这两个函数中没有任何有关对象的说明,setDate和 printDate函数如何知道打印的是那个对象的数据呢?
这一切都需要一个关键字this来解密。
4.2什么是this引用
this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该 引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
可能大家对文字概念很难理解我们用一张图来明确说明。
就是那个对象引用了该方法this就代表那个对象。
4.3this引用的特性
1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
2. this只能在"成员方法"中使用
3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法 对象的引用传递给该成员方法,this负责来接收 在代码层面来简单演示--->注意:下图右侧中的Date类也是可以通过编译的
总结:this的用法
1.可以通过this访问当前对象的成员变量
2.可以通过this访问当前对象的非静态的成员方法
3.可以通过this访问当前对象的其他构造方法
那什么时构造方法呢?其实就是通过this()进行构造的方法具体我们在下面了解。
(五).对象的构造和初始化
5.1如何给对象进行初始化
很明显这里我们只是定义了一个局部变量a但是我们并没有给a进行赋值这时很明显输出它就会报错,解决方法我们只需要给进行赋初值即可。
如果是对象呢?例如:
public static void main(String[] args) { Date d = new Date(); d.printDate(); d.setDate(2021,6,9); d.printDate(); }
需要调用之前写的SetDate方法才可以将具体的日期设置到对象中。
这时我们可以很明显的发现两个问题:
1. 每次对象创建好后调用SetDate方法设置具体日期,比较麻烦,那对象该如何初始化?
2. 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
5.2 构造方法
5.2.1概念
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且 在整个对象的生命周期内只调用一次。
public class Date { public int year; public int month; public int day; // 构造方法: // 名字与类名相同,没有返回值类型,设置为void也不行 // 一般情况下使用public修饰 // 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次 public Date(int year, int month, int day){ this.year = year; this.month = month; this.day = day; System.out.println("Date(int,int,int)方法被调用了"); } public void printDate(){ System.out.println(year + "-" + month + "-" + day); } public static void main(String[] args) { // 此处创建了一个Date类型的对象,并没有显式调用构造方法 Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了 d.printDate(); // 2021-6-9 } }
图中就是一个简单的构造方法,构造方法中我们需要注意的几点,构造方法的作用是对对象的成员进行初始化,并不负责给对象开辟空间。并且构造方法也可以发生重载。
5.2.2特性
1. 名字必须与类名相同
2. 没有返回值类型,设置为void也不行
3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
例如:
对比上面这两张图片,我们可以得出的结论时:
当你没有写任何的构造方法时Java会帮你默认提供一个不带参数的构造方法。但一旦有了构造方法之后Java也就不会帮你提供了。同时也构成了方法的重载。
5.3默认初始化
在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
public class Date { public int year; public int month; public int day; public Date(int year, int month, int day) { // 成员变量在定义时,并没有给初始值, 为什么就可以使用呢? System.out.println(this.year); System.out.println(this.month); System.out.println(this.day); } public static void main(String[] args) { // 此处a没有初始化,编译时报错: // Error:(24, 28) java: 可能尚未初始化变量a // int a; // System.out.println(a); Date d = new Date(2021,6,9); } }
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
1. 检测对象对应的类是否加载了,如果没有加载则加载
2. 为对象分配内存空间
3. 处理并发安全问题 比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突 数据类型 默认值 byte 0 char '\u0000' short 0 int 0 long 0L boolean false float 0.0f double 0.0 reference null
4. 初始化所分配的空间 即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值
5. 设置对象头信息
6. 调用构造方法,给对象中各个成员赋值
(六).封装
6.1封装的概念
我们常见的面向对象的三大特性:封装,继承、多态。而类和对象主要研究的就是封装,封装顾名思义就是省略细节直接要结果,比如我们日常生活中我们的我们的电脑一样,它供给我们使用的无非就只有三种,鼠标,键盘,和屏幕,但是它只有这几样东西?那肯定不是这样的,他是把那些精密的东西设计好我们直接拿来用,厂家直接把它封装起来给我们用。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
6.2访问限定符
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。
常用的访问限定符主要有public,private,protected,default.
比如:
public:可以理解为一个人的外貌特征,谁都可以看得到
default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道
protected常用在继承中,后面继承的博客中我会写。
default权限指的是什么都没写时的默认权限。
访问权限除了可以限制类中成员的可见性,也可以限制类的可见性。
public class Computer { private String cpu; // cpu private String memory; // 内存 public String screen; // 屏幕 String brand; // 品牌---->default属性 public Computer(String brand, String cpu, String memory, String screen) { this.brand = brand; this.cpu = cpu; this.memory = memory; this.screen = screen; } public void Boot(){ System.out.println("开机~~~"); } public void PowerOff(){ System.out.println("关机~~~"); } public void SurfInternet(){ System.out.println("上网~~~"); } } public class TestComputer { public static void main(String[] args) { Computer p = new Computer("HW", "i7", "8G", "13*14"); System.out.println(p.brand); // default属性:只能被本包中类访问 System.out.println(p.screen); // public属性: 可以任何其他类访问 // System.out.println(p.cpu); // private属性:只能在Computer类中访问,不能被其他类访问 } }
上图中就很好的说明了private,public,default的用法。但是我们需要注意的是在定义成员变量时我们通常使用private,在定义方法时通常使用public.
6.3 封装扩展之包
6.3.1包的概念
包顾名思义就是我们俗称的文件夹,我们为了更好的管理我们的文件夹我们通常会把类似相同的一些东西放到同一个包中,例如:
这里我们就将相似或者相同的东西放到了同一个包中。在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一 个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
6.3.2 导入包中的类
Java 中已经提供了很多现成的类供我们使用. 例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date 类.
public class Test { public static void main(String[] args) { java.util.Date date = new java.util.Date(); // 得到一个毫秒级别的时间戳 System.out.println(date.getTime()); } }
这种方法其实用起来比较麻烦我们可以运用import来导包,例如:
import java.util.Date; public class Test { public static void main(String[] args) { Date date = new Date(); // 得到一个毫秒级别的时间戳 System.out.println(date.getTime()); } }
6.3.3 自定义包
自定义包顾名思义就是我们自己创建一个包来实现代码。
基本原则:
1.在文件的最上方加上一个 package 语句指定该代码在哪个包中.
2.包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).
3.包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码.
4.如果一个类没有 package 语句, 则该类被放到一个默认包中.
6.3.4常见的包
1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
2. java.lang.reflect:java 反射编程包;
3. java.net:进行网络编程开发包。
4. java.sql:进行数据库开发的支持包。
5. java.util:是java提供的工具程序包。(集合类等) 非常重要
6. java.io:I/O编程开发包。
(七).static成员
7.1再谈学生类
使用前文中的学生类每创建一个对象它都有自己独特的名字,学号,年龄等信息它不能被共用,例如:
public class Student{ // ... public static void main(String[] args) { Student s1 = new Student("Li leilei", "男", 18, 3.8); Student s2 = new Student("Han MeiMei", "女", 19, 4.0); Student s3 = new Student("Jim", "男", 18, 2.6); } }
就这样我们都知道他们如果是一个班的同学他们肯定会在一个相同的教室里面上课,那么我们能否在类中定义一个变量来表示教室呢?很显然,是不行的这时我们就会用到static这个名词。之前在Student类中定义的成员变量,每个对象中都会包含一份(称之为实例变量),因为需要使用这些信息来描述 具体的学生。而现在要表示学生上课的教室,这个教室的属性并不需要每个学生对象中都存储一份,而是需要让所 有的学生来共享。在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对 象,是所有对象所共享的。
7.2static修饰成员变量
static修饰的成员变量称之为静态
成员变量,静态成员变量的最大特性是:不属于某个具体的对象,是所有对象所共享的。
静态成员变量特性:
1. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
3. 类变量存储在方法区当中
4. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
例如:
public class Student { public String name; public int age; public String stuNum; public static String classRoom="88305"; public Student(String name,int age,String stuNum){ this.name=name; this.age=age; this.stuNum=stuNum; } public static void main(String[] args) { System.out.println(Student.classRoom); Student student1=new Student("zhangsan",15,"1234"); Student student2=new Student("lisi",18,"1235"); Student student3=new Student("wangwu",20,"1236"); System.out.println(student1.classRoom); System.out.println(student2.classRoom); System.out.println(student3.classRoom); } }
我们通过上面的代码进行调试我们可以发现静态成员变量并没有存储到某个具体的对象中。 具体的我们可以用下图来表达:
它很好的说明了静态成员变量是所有类中的变量所共有的,并且它不属于某一个对象,也不是从某个对象中开辟空间来存放的。
7.3static修饰成员方法
上面讲述了静态成员变量的用法,接下来就是关于静态成员方法的讲解。
一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性如何 在类外访问呢?例如:
如果我们直接这样来用的话,它会因为是被private修饰而不能成功运行,那么我们该如何来解决呢?其实很好办,Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过 静态方法来访问的。
解决如下:
public class Student{ // ... private static String classRoom = "Bit306"; // ... public static String getClassRoom(){ return classRoom; } } public class TestStudent { public static void main(String[] args) { System.out.println(Student.getClassRoom()); } }
静态方法的特性:
1. 不属于某个具体的对象,是类方法
2. 可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者
3. 不能在静态方法中访问任何非静态成员变量
4. 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用
个人总结如下:
(八).代码块
一般由{}定义的一段代码称之为代码块,种类有普通代码块,构造块,静态块等。
8.1普通代码块
普通代码块:定义在方法中的代码块
public class Main{ public static void main(String[] args) { { //直接使用{}定义,普通方法块 int x = 10 ; System.out.println("x1 = " +x); } int x = 100 ; System.out.println("x2 = " +x); } } // 执行结果 x1 = 10 x2 = 100
8.2构造代码块
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
public class Student{ //实例成员变量 private String name; private String gender; private int age; private double score; public Student() { System.out.println("I am Student init()!"); } //实例代码块 { this.name = "bit"; this.age = 12; this.sex = "man"; System.out.println("I am instance init()!"); } public void show(){ System.out.println("name: "+name+" age: "+age+" sex: "+sex); } } public class Main { public static void main(String[] args) { Student stu = new Student(); stu.show(); } } // 运行结果 I am instance init()! I am Student init()! name: bit age: 12 sex: man
8.4 静态代码块
public class Student{ private String name; private String gender; private int age; private double score; private static String classRoom; //实例代码块 { this.name = "bit"; this.age = 12; this.gender = "man"; System.out.println("I am instance init()!"); } // 静态代码块 static { classRoom = "bit306"; System.out.println("I am static init()!"); } public Student(){ System.out.println("I am Student init()!"); } public static void main(String[] args) { Student s1 = new Student(); Student s2 = new Student(); } }
注意事项:
静态代码块不管生成多少个对象,其只会执行一次
静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
实例代码块只有在创建对象时才会执行
(九) .对象的打印
public class Person { String name; String gender; int age; public Person(String name, String gender, int age) { this.name = name; this.gender = gender; this.age = age; } public static void main(String[] args) { Person person = new Person("Jim","男", 18); System.out.println(person); } } // 打印结果:day20210829.Person@1b6d3586
这里我们如果想打印成员变量该怎么办呢?很简单用toString,如下:
public class Person { String name; String gender; int age; public Person(String name, String gender, int age) { this.name = name; this.gender = gender; this.age = age; } @Override public String toString() { return "[" + name + "," + gender + "," + age + "]"; } public static void main(String[] args) { Person person = new Person("Jim","男", 18); System.out.println(person); } } // 输出结果:[Jim,男,18]
好了以上就是关于类和对象的全部理解,我们下期在再见!!!