目录
1. 面向对象的初步认知
1.1 什么是面向对象
面向过程:按照每个步骤依次进行
我们以洗碗为例
在洗碗的过程中我们需要把每个事情都过一遍
面向对象:完成某件事的时候,只需要和对象之间进行交互,那么这个事情就可以完成。
以 面向对象方式来进行处理,就不关注洗碗的过程 ,具体洗碗机是怎么洗碗的,如何来甩干的,用户不用去关心,只需要将碗放进洗碗机,导入洗洁精,启动开关即可, 通过对象之间的交互来完成的 。
2. 类定义和使用
2.1 简单认识类 和类的定义格式
类是用来对一个实体 ( 对象 ) 来进行描述的 ,主要描述该实体 ( 对象 ) 具有哪些属性 ( 外观尺寸等 ) ,哪些功能 ( 用来干啥 ) ,描述完成后计算机就可以识别了。
类:1,定义一个类【类型:int byte char ......】【自定义类型】语法格式:// 创建类 class ClassName{ //className:类名 field; // 字段(属性) 或者 成员变量 method; // 行为 或者 成员方法 }
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法简单定义格式:class Student { //成员变量:成员变量要定义在类的内部,方法的外部 String name; int age; //方法-》行为 public void eat(){ System.out.println(name+"正在吃饭"); } public void sleep(){ System.out.println(name+"正在睡觉"); } public void study(){ System.out.println(name+"正在学习"); } }
注意事项:
- 类名注意采用大驼峰定义
- 成员前写法统一为public.
- 此处写的方法不带 static 关键字.
- 成员变量要定义在类的内部,方法的外部
3. 类的注意事项
1.一般一个文件当中只定义一个类
error:
不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改
注意事项:
- 一般一个文件当中只定义一个类
- main方法所在的类一般要使用public修饰
- public修饰的类必须要和文件名相同
- 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改
4. 类的实例化
4.1 什么是实例化
定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上的:PetDog类和Student类。它们都是类(一种新定 义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。
由类产生对象的过程---->类的实例化,在java中采用new关键字,配合类名来实例化对象
class Student {
//成员变量
String name;
int age;
//方法-》行为
public void eat(){
System.out.println(name+"正在吃饭");
}
public void sleep(){
System.out.println(name+"正在睡觉");
}
public void study(){
System.out.println(name+"正在学习");
}
}
public class Test {
public static void main(String[] args) {
//通过new实例化了一个对象
Student student1 = new Student();
student1.name="李华";
student1.age=18;
student1.eat();
student1.sleep();
student1.study();
Student student2 = new Student();
student2.name="阿文";
student2.age=19;
student2.eat();
student2.sleep();
student2.study();
}
}
在这里我们是通过“ . ”来访问对象中的属性和方法
但是当我们的成员变量没有初始化数值的时候是什么呢?
class Student { //成员变量 String name; int age; //方法-》行为 public void eat(){ System.out.println(name+"正在吃饭"); } public void sleep(){ System.out.println(name+"正在睡觉"); } public void study(){ System.out.println(name+"正在学习"); } } public class Test { public static void main(String[] args) { Student student=new Student(); System.out.println(student.name); System.out.println(student.age); } }
我们可以知道当成员变量么有初始化时:
1,引用数据类型->null
2,基本数据类型(int byte long short...)->0
3,boolean->false
4,char->'\u0000'
注意事项:
- new 关键字用于创建一个对象的实例.
- 使用 ‘ . ’ 来访问对象中的属性和方法.
- 同一个类可以创建多个实例.
4.2 类实例化后的内存关系
当我们实例化一个对象后,只会把类中的成员/属性实例化到对象中,而方法并不会在对象中存储,当调用某个对象的方法时,还是会在栈上创建函数栈帧去进行计算
注意:
- 创建的对象只会存储成员/属性到对象中,方法不会出现在对象中
- 当调用对象的方法时,还是会从栈中创建栈帧去计算
4.3 类和对象的说明
1. 类只是 一个 模型 一样的东西,用来对一个实体进行描述,限定了类有哪些成员 .2. 类是一种自定义的类型 ,可以用来定义变量 .3. 一个类可以实例化出多个对象, 实例化出的对象 占用实际的物理空间,存储类成员变量4. 做个比方。 类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图 ,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空 间
5. this引用
5.1为什么要有this
先看一个日期类的例子:
class Date { public int year; public int month; public int day; public void setDate(int y, int m, int d) { year = y; month = m; day = d; } public void printDate() { System.out.println(year + "/" + month + "/" + day); } } public class TestDemo { 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.setDate(2022,4,15); d2.setDate(2022,4,16); d3.setDate(2022,4,17); // 打印日期中的内容 d1.printDate(); d2.printDate(); d3.printDate(); } }
在这里有一个问题形参名不小心与成员变量名相同:
假如我将类中的setDay方法改成如下,那方法知道那个是成员变量那个是形参名吗,到最后打印就会出问题如果要区分那就需要this引用了此时方法中的局部变量优先
public void setDay(int year, int month, int day){//局部变量优先 year = year; month = month; day = day; }
如果要区分那就需要this引用了
public void setDay(int year, int month, int day){ this.year = year; this.month = month; this.day = day; }
5.2什么是this引用
this引用:this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问
所以我建议大家在这种调用时都加上"this",能用则用。
5.3 this引用的特性
1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
2. this只能在"成员方法"中使用
3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
6. 对象的构造及初始化
6.1 如何初始化对象
通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败。
public static void main(String[] args) { int a; System.out.println(a); } // Error:(26, 28) java: 可能尚未初始化变量a
要让上述代码通过编译,非常简单,只需在正式使用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. 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
因为在上方我们说过 :
我们可以知道当成员变量么有初始化时:
1,引用数据类型->null
2,基本数据类型(int byte long short...)->0
3,boolean->false
4,char->'\u0000'
6.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 } }
6.2.2 特性
1. 名字必须与类名相同
2. 没有返回值类型,设置为void也不行
3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)public class Date { public int year; public int month; public int day; // 无参构造方法 public Date(){ this.year = 1900; this.month = 1; this.day = 1; } // 带有三个参数的构造方法 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(); } }
5. 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
public class Date { public int year; public int month; public int day; public void printDate(){ System.out.println(year + "-" + month + "-" + day); } } public static void main(String[] args) { Date d = new Date(); d.printDate(); }
上述Date类中,没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。
注意:一旦用户定义,编译器则不再生成。
所以要想好要不要定义构造方法public class Date { public int year; public int month; public int day; 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(); } /* Error:(26, 18) java: 无法将类 extend01.Date中的构造器 Date应用到给定类型; 需要: int,int,int 找到: 没有参数 原因: 实际参数列表和形式参数列表长度不同 */
对于构造方法存在简易的构造方法生成
6. 构造方法中,可以通过this调用其他构造方法来简化代码
public class Date { public int year; public int month; public int day; // 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复 // 此处可以在无参构造方法中通过this调用带有三个参数的构造方法 // 但是this(1900,1,1);必须是构造方法中第一条语句 public Date(){ //System.out.println(year); 注释取消掉,编译会失败 this(2022, 5, 11); //this.year = 1900; //this.month = 1; this.day = 1; } // 带有三个参数的构造方法 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 date=new Date(); date.printDate(); } }
在这里面的this是调用另一个带有3个参数的构造方法
1.this()必须在构造方法中调用
2.this()必须在构造方法中的第一行
3.this()不能在本构造方法中调用自己形成环,这样会死循环
7.this.func;调用当前对象的成员方法
public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; this.printDate(); }
6.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); } }
关于这个问题我们已经在6.1的第二个问题稍微讲解了一下,需要的话可以返回上方看一下
要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:
Date d = new Date(2022,5,2);
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
1.检测对象对应的类是否加载了,如果没有加载则加载
2.为对象分配内存空间
3.处理并发安全问题
比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突。
4.初始化所分配的空间
即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:
数据类型 默认值 byte 0 char '\u0000' short 0 int 0 long 0L boolean false float 0.0f double 0.0 reference null 5.设置对象头信息
6.调用构造方法,给对象中各个成员赋值
7.封装
7.1 封装的概念
面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说
就是套壳屏蔽细节不想让类外看到我具体的实现细节,所以,我通过技术手段将这些细节进行封装,对这个类的细节 进行隐藏,提供一些公开的接口,让你来进行交互
比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用
户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互
7.2访问修饰限定符(了解)
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认
知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符
比如:
public:可以理解为一个人的外貌特征,谁都可以看得到
default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道:只能在当前类中访问
【说明】
protected主要是用在继承中,继承部分详细介绍
default权限指:什么都不写时的默认权限
访问权限除了可以限定类中成员的可见性,也可以控制类的可见性
7.3private实现封装
我新建了一个类->TestDemo,在public修饰时,哪哪都可以用,我在TestDemo中也可以运用
我能在另外一个类中再访问,其原因是
都为public修饰
但是当我将year改为private类型的后
此时year只能在当前类里面访问:也就是说被private修饰后只能在类中使用被修饰的成员变量或者方法,就是说在类外不能实现其封装的属性了
- 被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.
- 被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用.
如果 想在private的情况下来使TestDemo实现year的功能
我们要为这个year提供一个公开的接口
当我们对三个对象都进行private修饰的时候
我们可以使用快捷键来代替手敲代码来得到setmonth和setday以及getmonth和getday:
后面的操作步骤同上
目前对于成员的赋值:
1.定义字段的时候,同时初始化->就地初始化
public class Date { public int year = 1900; public int month = 1; public int day = 1; public Date(){ } public Date(int year, int month, int day) { } public static void main(String[] args) { Date d1 = new Date(2021,6,9); Date d2 = new Date(); } }
2.不初始化
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); } }
3.在类外,通过对象的引用直接赋值
student.name="李华"; student.age=18;
4.通过构造方法初始化
public class Date { public int year; public int month; public int day; // 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复 // 此处可以在无参构造方法中通过this调用带有三个参数的构造方法 // 但是this(1900,1,1);必须是构造方法中第一条语句 public Date(){ //System.out.println(year); 注释取消掉,编译会失败 this(2022, 5, 11); //this.year = 1900; //this.month = 1; this.day = 1; } // 带有三个参数的构造方法 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 date=new Date(); date.printDate(); } }
5.提供提供get和set来实现
7.3 封装扩展之包
7.3.1 包的概念
在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件
包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件
下,也可以对某个文件夹下的音乐进行更详细的分类
相当于通过定义一些java文件夹把一些Java文件归类到一些文件夹当中
7.3.2 导入包中的类
当我们去创建一个类后发现
多出来了一行:
package www.wwwsuper.com;这个是用来声明当前Java文件 是在哪个包低下
在我们平时的编程中我们也运用到过包
通过import来导包
我们有两种方式来实现
但是我们可以发现Date有两种类型的包,出现冲突
我们只能通过
在前方定义来区分!
在我们重复使用静态方法时我们可以使用import static导入包中静态的方法和字段。
注意事项: import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要.import 只是为了写代码的时候更方便. import 更类似于 C++ namespace 和 using
7.3.3 自定义包
基本规则
在文件的最上方加上一个 package 语句指定该代码在哪个包中.
1.包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).
2.包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码.
3.如果一个类没有 package 语句, 则该类被放到一个默认包中.
操作步骤
1. 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包操作方法:
我们可以去文件夹里查看创建了什么:![]()
![]()
7.3.4 包的访问权限控制举例
Computer类位于www.bite.demo1包中,TestComputer位置www.bite.demo2包中:
package www.bite.demo1; public class Computer { private String cpu; // cpu private String memory; // 内存 public String screen; // 屏幕 String brand; // 品牌 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("上网~~~"); } }
package www.bite.demo2; import www.bite.demo1.Computer; public class TestComputer { public static void main(String[] args) { Computer p = new Computer("HW", "i7", "8G", "13*14"); System.out.println(p.screen); // System.out.println(p.cpu); // 报错:cup是私有的,不允许被其他类访问 // System.out.println(p.brand); // 报错:brand是default,不允许被其他包中的类访问 } } // 注意:如果去掉Computer类之前的public修饰符,代码也会编译失败
7.3.5 常见的包
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编程开发包。