📜个人简介
⭐️个人主页:摸鱼の文酱博客主页🙋♂️
🍑博客领域:java编程基础,mysql
🍅写作风格:干货,干货,还是tmd的干货
🌸精选专栏:【Java】【mysql】 【算法刷题笔记】
🎯博主的码云gitee,平常博主写的程序代码都在里面。
🚀支持博主:点赞👍、收藏⭐、留言💬
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!
💛前言:
相信大家在接触java时就一定听到过:Java是一门面向对象的编程语言,而我们之前学习的c语言是面向过程的编程语言.所以许多童鞋在学习java的过程中,甚至学完了都不知道这个面向对象到底意味着什么,体现在什么地方.
然而,想要学好java这门语言,掌握面向对象是必须的,尤其是当我们面对一个大项目,几十万行代码时,面向对象就会让你知道它的神奇之处.
那么今天就让我来带大家深挖面向对象的细节,相信各位童鞋看完这篇文章就能豁然开朗,彻底理解面向对象,
(文章目录带⭐️为需要重点掌握的)
准备好了吗? 我们要开始了!
面向对象--类和类的成员
)
👓认识面向对象
首先,上正菜🍔 前,先让我们来点开胃小菜🍟:先来认识一下面向对象是什么
🚩说到
面向对象(OOP)
,就不免要提到
面向过程(POP)
.
❓ 那么,这"两兄弟"究竟有什么不一样的地方?
1️⃣ 二者都是一种思想:面向对象是相对于面向过程而言的。
面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做
。
面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做
。
2️⃣ 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象
、
分类
、
继承
、
聚合
、
多态
等。
3️⃣.面向对象的思想将程序员从面向过程的执行者转化为了面向对象的指挥者.
上面是比较官方的对二者区别的阐述,但是我相信大家现在都有一种"听君一席话,如听一席话"的感觉.
还是没有理解.没关系.我举一个实际的例子来帮助大家理解上述内容:
一个经典的示例:把大象装进冰箱中
如果我们以面向过程的思想来完成上述动作时,需要进行的操作就是:
先打开冰箱门 --> 把大象塞进去 -->关上冰箱门
…这一系列动作就完成了这个操作.
那如果以面向对象来完成呢?
前面已经说过,面向对象要考虑的是谁来做的问题.那就让我们来看一下,这个操作一共涉及到了几个对象 —人
,
冰箱
,
大象
,一共三个对象.对于人来讲:要打开(关闭)冰箱门,还要完成将大象装进冰箱的操作. 对于冰箱来讲:要完成冰箱门的打开和关闭. 最后对于大象来讲:要进入冰箱
OK,看完上述例子,相信各位聪明的小伙伴已经初步认识了什么是面向对象.😎
我们还要理解一下面向对象的两个要素:类和对象
很多小伙伴在学习java过程中对类和对象的理解不够,导致对后面的学习造成影响.所以我们需要先来关注一下类和对象:
👓理解类和对象
类(Class)和对象(Object)是面向对象的核心概念。
1️⃣ 类是对一类相似事物的描述,是抽象的、概念上的定义
2️⃣ 对象是实际存在的该类事物的每个个体,因而也称为实例(instance),是具体存在的个体。
❓那么到底应该怎么理解这两个概念呢?
🔎 类就是对一些具有共性特征,并且行为相似的个体的描述。
比如:小明和小红都有名字、年龄、性别等一些属性,并且两人都能够学习、与人交流、等相似的行为。由于这两个人具有这些共性的地方,所以我们把它抽象出来,定义为一个类——人类。
而对象是真正具体的存在。
比如:小明、小红就是人这个类中的个体(对象)。
类的实例化
🚩用类类型创建对象的过程,称为类的实例化
语法格式
// 创建类
class <class_name>{
field;//成员属性
method;//成员方法
}
// 实例化对象<class_name><对象名>= new <class_name>();
- 类只是一个模型一样的东西,限定了类有哪些成员.
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
示例:
class Person {
publicint age;//属性public String name;public String sex;public void eat() {//方法
System.out.println("吃饭!");
}
public void sleep() {
System.out.println("睡觉!");
}
}
public class 类和对象 {
public static void main(String[] args) {
Person person = new Person();//通过new实例化对象//产生多个对象
Person person2 = new Person();
Person person3 = new Person();
}
}
小结
1.new 关键字用于创建一个对象的实例.
2.使用 . 来访问对象中的属性和方法.
3.同一个类可以创建对个实例.
接下来,我将从1️⃣:类和类的成员, 2️⃣ :面向对象的三大特征, 3️⃣ :其它关键字这三大方面介绍面向对象的特点.本篇内容为类和类的成员
🚩面向对象程序设计的重点就是类的设计
class Person{}
像这样,其实就已经是一个person类了.但是这个类内部什么都没有,只是一个空壳,没有灵魂
我们要对他进行设计,从而让它有一定作用.
🚩设计类的本质就是设计类的成员
其中,类的成员有:属性,方法,构造器,代码块,内部类
在这五类之中,最为基础,重要的就是:属性(Field 也叫做变量,也有叫字段或域的), (成员)方法(Method).
🌟 1.属性(变量)
💙变量分类:
🚩变量根据声明位置的不同可以分为成员变量和局部变量两种
🌀局部变量
💎声明在方法内部(方法的形参、内部类、代码块、构造器(构造器的形参))的是局部变量
❄️声明格式
变量类型 变量名 = 变量值;
❄️特点
1️⃣.声明时不能使用访问限定修饰符,它的权限跟随方法(或构造器)的权限.
2️⃣.遵循先赋值后使用的原则,未经初始化的局部变量不可直接使用(注意:方法的形参为特殊,它的初始化为方法调用时传入的值;)
意味着我们调用局部变量前,一定要显式赋值
3️⃣.局部变量存放在栈空间
示例:
class Person {
public String name;public void eat() {//方法int a =10;int b;
System.out.println("吃饭!");
}
}
❄️小结
🌀成员变量
💎声明在类的内部,方法的外部的是成员变量
声明格式:
权限修饰符 (static) 变量类型 变量名 = 变量值;
根据声明时有无"static"修饰,还可以分为:普通成员变量(不用static修饰)和静态成员变量
接下来会根据普通成员变量(也叫做实例变量)和静态成员变量(也叫做类变量)的相同点和不同点来介绍.
▶️相同点
1️⃣.都需要先声明后使用,可以采用默认值(0/null),也可以初始化其他值
默认初始化的初始化值:
整型变量:byte、short、int、long ---->0
浮 点 型:float、double ---->0.0
布 尔 型:boolean ---->false
字 符 型:char ---->0 或’\u0000’
引用类型:接口,数组、类 ---->null
2️⃣.可以声明权限修饰符;修饰符有:public 、缺省 、protected、private ;
3️⃣.实例变量都有其所在的一个作用域{},只有在其定义的作用域中有效;
示例:
class Person {
private static String name;//静态成员变量publicint age;//普通成员变量
}
class Animal{
public String a_name;
}
public class 类和对象 {
public static void main(String[] args) {
Animal animal = new Animal();
animal.age //age是Person类中定义的,只能被Person类的对象调用
}
}
▶️不同点
1️⃣.声明方式不同
🔺实例变量不需要static修饰
🔻类变量需要static修饰
2️⃣.调用方式不同
🔺实例变量不经过实例化无法调用.通过对象.属性修改此实例变量;
🔻类变量不仅可以通过对象调用,也可以采用类名 . 类变量的方法调用;
class Person {
public static int age;//静态成员变量public String name;//普通成员变量
}
public class 类和对象 {
public static void main(String[] args) {
Person person = new Person();//通过new实例化对象
System.out.println(person.sex);//对象.实例变量
System.out.println(person.age);//对象.类变量
System.out.println(Person.age);//类.类变量
System.out.println(Person.name);//不能直接类.实例变量
}
}
3️⃣.生命周期不同
🔺实例变量随着对象的创建而产生,随着对象的回收而被释放;
🔻类变量随着类的加载而产生,随着类的消失而消失
4️⃣.与对象关系不同
🔺实例变量每个对象特有一份实例变量且互不干扰,所以也叫对象的特有数据.
🔻类变量为类的所有对象共享,一经改变,后续调用为改变后的值,所以也叫对象的共享数据;
示例:
class Person {
public static String name;//静态成员变量publicint age;//普通成员变量public String sex;
}
public class 类和对象 {
public static void main(String[] args) {
Person person1 = new Person();//通过new实例化对象
person1.name ="张三";
person1.age=10;
System.out.println(person1.name);
System.out.println(person1.age);
System.out.println("=========================================");
Person person2 = new Person();
System.out.println(person2.name);
System.out.println(person2.age);
}
}
5️⃣.存储空间不同
🔺实例变量存储在堆内存的对象中
🔻类变量分配在方法区的静态区,类变量早于方法的创建且优先于对象存在;
内存解析图
💙匿名对象
我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做
匿名对象
。
如: new Person().shout();
📕使用情况
1.如果对一个对象只需要进行一次方法调用
,那么就可以使用匿名对象。
2.我们经常将匿名对象作为实参
传递给一个方法调用。
💙关于对象数组
什么是对象数组?
我们可以类比学过的c语言中的结构体数组
来认识它.
所谓的对象数组,就是指包含了一组相关的对象,但是在对象数组的使用中一定要清楚一点:数组一定要先开辟空间,但是因为其是引用数据类型,所以数组里面的每一个对象初始化都是null值,则在使用的时候数组中的每一个对象必须分别进行实例化操作
。
class Student{
int number;//学号int state =1;//年级int score;//成绩
}
public class 对象数组 {
public static void main(String[] args) {
Student[] stus = new Student[5];
stus[0]= new Student();
System.out.println(stus[0].state);//1
System.out.println(stus[1]);//null
System.out.println(stus[1].number);//报错,此时的stus[1]还未实例化对象,为null
stus[1]= new Student();
System.out.println(stus[1].number);//0
}
}
内存解析图:
⭐️成员变量和局部变量的区别
💙小结
🌟 2.方法
💙什么是方法
1️⃣.方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中
也称为函数或过程。
2️⃣.将功能封装为方法的目的是,可以实现代码重用,简化代码
3️⃣Java里的方法不能独立存在,所有的方法必须定义在类里。
4️⃣.我们看一个类的功能是否强大,主要是看他内部的方法是否丰富.
💙方法的声明格式
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
方法体程序代码
return 返回值;
}
其中
1️⃣.权限修饰符:public protected 缺省 private;
2️⃣.返回值类型:
a.没有返回值: void
b.有返回值,声明出返回值的类型。与方法体中“return 返回值” 搭配使用
3️⃣.方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意” 具体可以查看变量命名规则
4️⃣.形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,
”隔开
5️⃣.返回值:方法在执行完毕后返还给调用它的程序的数据。
📃思考
如何理解方法返回值类型为void的情况 ?
根据声明时有无"static"修饰,可以将方法分为普通成员方法(不用static修饰)和静态成员方法
💙方法的分类
无返回值有返回值无形参void 方法名() {}返回值的类型 方法名() {}有形参void 方法名(形参列表)返回值的类型 方法名(形参列表) {}
💙方法的调用
💎方法通过方法名被调用,且只有被调用才会执行。
方法调用的过程分析
注 意:
1️⃣方法被调用一次,就会执行一次
2️⃣没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可以不必使用return语句。如果使用,仅用来结束方法。
3️⃣定义方法时,方法的结果应该返回给调用者,交由调用者处理。
4️⃣方法中只能调用方法或属性, 不可以在方法内部定义方法。
⭐️方法的重载
🌀重载的概念
Java 允许同一个类中定义
多个同名方法
,只要它们的
形参列表不同
即可。如果同一个类中包含了
两个或两个以上方法名相同
的方法,但形参列表不同,这种情况被称为
方法重载
(overload)
🌀重载的特点
💎方法重载的要求是 两同一不同:同一个类中方法名相同,参数列表不同。至于方法的其他部分,如方法返回值类型、修饰符等,与方法重载没有任何关系。
示例:
public class OverLoading {
public void max(int a,int b) {
// 含有两个int类型参数的方法
System.out.println(a > b ? a : b);
}
public void max(double a,double b) {
// 含有两个double类型参数的方法
System.out.println(a > b ? a : b);
}
public void max(double a,double b,int c) {
// 含有两个double类型参数和一个int类型参数的方法double max =(double)(a > b ? a : b);
System.out.println(c > max ? c : max);
}
public static void main(String[] args) {
OverLoading ol = new OverLoading();
System.out.println("1 与 5 比较,较大的是:");
ol.max(1,5);
System.out.println("5.205 与 5.8 比较,较大的是:");
ol.max(5.205,5.8);
System.out.println("2.15、0.05、58 中,较大的是:");
ol.max(2.15,0.05,58);
}
}
👉使用重载方法,可以为编程带来方便,其实就是避免出现繁多的方法名,有些方法的功能是相似的,如果重新建立一个方法,重新取个方法名称,会降低程序可读性。
❓看到这里你肯定想问:为什么返回值类型不同不能用来当重载的条件?
对于int f( ) { }
和
void( ) { }
两个方法,如果这样调用
int result = f();
,系统可以识别是调用返回值类型为
int
的方法
但 Java 调用方法时可以忽略方法返回值,如果采用如下方法来调用f();
,你能判断是调用哪个方法吗?
如果你尚且不能判断,那么 Java 系统也会糊涂。在编程过程中有一条重要规则就是不要让系统糊涂,系统一糊涂,肯定就是你错了。因此,Java 里不能用方法返回值类型作为区分方法重载的依据❗️。
💙可变形参的方法
JavaSE 5.0
中提供了
Varargs(variable number of arguments)机制
,允许直接定义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参
//JDK 5.0以前: 采用数组形参来定义方法,传入多个同一类型变量publicstaticvoidtest(int a ,String[] books);//JDK5.0: 采用可变个数形参来定义方法,传入多个同一类型变量publicstaticvoidtest(int a ,String…books);
💡 说明:
1️⃣.声明格式: 方法名(参数的类型名 …参数名)
2️⃣ .可变参数:方法参数部分指定类型的参数个数是可变多个: 0个, 1个或多个
3️⃣ . 可变个数形参的方法与同名的方法之间,彼此构成重载
4️⃣.可变参数方法的使用与方法参数部分使用数组是一致的,不能构成重载.
5️⃣.方法的参数部分有可变形参,需要放在形参声明的最后
6️⃣. 在一个方法的形参位置,最多只能声明一个可变个数形参
👻举个例子:
classTestOverload{publicvoidtest(String[] msg){System.out.println("含字符串数组参数的test方法 ");}publicvoidtest1(String... books){System.out.println("****形参长度可变的test1方法****");}publicvoidtest1(String book){System.out.println("****与可变形参方法构成重载的test1方法****");}}publicclass 可变个数形参的方法 {publicstaticvoidmain(String[] args){TestOverloadto=newTestOverload();to.test(newString[]{"aa"});//将执行第一个test方法to.test1("aa","bb");//下面将执行第一个test1方法to.test1("a");//下面将执行第二个test1方法to.test1();//下面将执行第一个test1方法}}
🙉 最后输出的结果中,第二个和第四个输出都是调用了可变形参的方法.也就是说:可变形参的个数范围在
[0,+∞).
😸 其中,我们可以看到,当类中定义了String类型的可变个数形参方法时,就不能再存在形参为String数组的同名方法,无法构成重载,是因为在编译器看来它们的本质上是一样的.也就是说二者无法共存
⭐️方法参数的值传递机制
💎方法,必须由其所在类或对象调用才有意义。若方法含有参数:
形参
:方法声明时的参数
实参
: 方法调用时实际传给形参的参数值
❓Java的实参值如何传入方法呢?
Java里方法的参数传递方式只有一种:值传递 。 即将实际参数值的副本(复制品)
传入方法内,而参数本身不受影响。
形参是基本数据类型
:将实参基本数据类型变量的“
数据值
”传递给形参
形参是引用数据类型
:将实参引用数据类型变量的“
地址值
”传递给形参
⭐️方法的参数传递
💎基本数据类型的参数传递
publicstaticvoidmain(String[] args){int x =5;System.out.println("修改之前x = "+ x);// 5change(x);// x是实参System.out.println("修改之后x = "+ x);// 5}publicstaticvoidchange(int x){System.out.println("change:修改之前x = "+ x);
x =3;System.out.println("change:修改之后x = "+ x);}
💎引用数据类型的参数传递
publicstaticvoidmain(String[] args){Person obj =newPerson();
obj.age =5;System.out.println("修改之前age = "+ obj.age);// 5// x是实参change(obj);System.out.println("修改之后age = "+ obj.age);// 3}publicstaticvoidchange(Person obj){System.out.println("change:修改之前age = "+ obj.age);
obj.age =3;System.out.println("change:修改之后age = "+ obj.age);}classPerson{int age;}
💎引用数据类型的参数传递
publicstaticvoidmain(String[] args){Person obj =newPerson();
obj.age =5;System.out.println("修改之前age = "+ obj.age);// 5// x是实参change(obj);System.out.println("修改之后age = "+ obj.age);// 5}publicstaticvoidchange(Person obj){
obj =newPerson();System.out.println("change:修改之前age = "+ obj.age);
obj.age =3;System.out.println("change:修改之后age = "+ obj.age);}classPerson{int age;}
💙方法的递归
💎递归方法:一个方法体内调用它自身。
1️⃣.方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执
行无须循环控制。
2️⃣递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死
循环
⭐️方法的重写
🌀定义:
在
子类
中如果创建了一个与
父类
中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为
方法重写
(override),又称为方法覆盖。
当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。
由于方法的重写必须是建立在发生继承的基础上的,所以方法的重写将在下一篇介绍继承机制时讲解
💙小结
🌟 3.构造器
🚩所有的类都有构造器,构造器是区分类还是接口的关键.
🔺构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作
new 执行过程:
1️⃣为对象分配内存空间
2️⃣调用对象的构造方法
💙 语法格式:
修饰符 类名 (参数列表) {
初始化语句;
}
⭐️ 构造器的特征
1️⃣它具有与类相同的名称
2️⃣它不声明返回值类型。(与声明为void不同)
3️⃣不能被static、 final、 synchronized、 abstract、 native修饰,不能有return语句返回值
4️⃣每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)
💙 构造器的作用
💎构造器的作用是1️⃣创建对象2️⃣给对象进行初始化
💙 构造器重载
1️⃣构造器一般用来创建对象的同时初始化对象。
2️⃣构造器重载使得对象的创建更加灵活,方便创建各种不同的对象。
3️⃣构造器重载,参数列表必须不同
示例:
publicclassPerson{//构造器重载举例privateString name;privateint age;privateDate birthDate;publicPerson(String n,int a,Date d){
name = n;
age = a;
birthDate = d;}publicPerson(String n,int a){
name = n;
age = a;}publicPerson(String n,Date d){
name = n;
birthDate = d;}publicPerson(String n){
name = n;
age =30;}}
注意事项
:
1️⃣如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数
2️⃣若类中定义了构造方法,则默认的无参构造将不再生成.
3️⃣构造方法支持重载. 规则和普通方法的重载一致
代码示例:
classPerson{privateString name;//实例成员变量privateint age;privateString sex;//默认构造函数 构造对象publicPerson(){this.name ="caocao";this.age =10;this.sex ="男";}//带有3个参数的构造函数publicPerson(String name,int age,String sex){this.name = name;this.age = age;this.sex = sex;}publicvoidshow(){System.out.println("name: "+name+" age: "+age+" sex: "+sex);}}publicclassMain{publicstaticvoidmain(String[] args){Person p1 =newPerson();//调用不带参数的构造函数 如果程序没有提供会调用不带参数的构造函数
p1.show();Person p2 =newPerson("zhangfei",80,"男");//调用带有3个参数的构造函数
p2.show();}}
关于上述代码设计构造器时用到的"this"关键字,将在后续介绍其它关键字时讲解
💙小结
⛽️属性赋值过程:
截止到目前,我们讲到了很多位置都可以对类的属性赋值。现总结这几个位置,并指明赋值的先后顺序。
赋值的位置
:
①默认初始化
②
显式初始化
③
构造器中初始化
④
通过“对象.属性“或“对象.方法”的方式赋值
⑤
在静态代码块中初始化
赋值的先后顺序:
⑤ - ① - ② - ③ - ④
🌟 4.代码块
字段的初始化方式有:
- 就地初始化
- 使用构造方法初始化
- 使用代码块初始化
前两种方式前面已经学习过了, 接下来我们介绍第三种方式, 使用代码块初始化
💙什么是代码块
💎使用 {} 定义的一段代码.
🔥静态代码块优先执行
如果定义了多个静态或者非静态代码块,照定义的先后顺序执行;
💙 分类
根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块
构造块
静态块
同步代码块
(后续讲解多线程部分再谈)
🌀构造块
💎构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。
🔮作用:一般用于初始化实例成员变量。
示例:
classPerson{privateString name;//实例成员变量privateint age;privateString sex;publicPerson(){System.out.println("I am Person init()!");}//实例代码块{this.name ="bit";this.age =12;this.sex ="man";System.out.println("I am instance init()!");}publicvoidshow(){System.out.println("name: "+name+" age: "+age+" sex: "+sex);}}publicclassMain{publicstaticvoidmain(String[] args){Person p1 =newPerson();
p1.show();}}
🌀静态代码块
💎使用static定义的代码块。一般用于初始化静态成员属性。
🔮作用:初始化类的加载信息
🌱特性
1️⃣静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
2️⃣静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行
3️⃣内部只能调用当前类中静态的属性、方法。不能调用非静态的属性、方法
示例:
classPerson{privateString name;//实例成员变量privateint age;privateString sex;privatestaticint count =0;//静态成员变量 由类共享数据 方法区publicPerson(){System.out.println("I am Person init()!");}//实例代码块{this.name ="bit";this.age =12;this.sex ="man";System.out.println("I am instance init()!");}//静态代码块static{
count =10;//只能访问静态数据成员System.out.println("I am static init()!");}publicvoidshow(){System.out.println("name: "+name+" age: "+age+" sex: "+sex);}}publicclass 类和对象 {publicstaticvoidmain(String[] args){Person p1 =newPerson();Person p2 =newPerson();//静态代码块是否还会被执行?}}
🌀非静态代码块
💎普通代码块:定义在方法中的代码块
🔮作用:用来初始化对象的属性信息;
🌱特性
1️⃣随着对象的创建而执行;
2️⃣可以调用当前类的方法和属性
3️⃣每创建一个对象,都会执行一次
publicclass 类和对象 {publicstaticvoidmain(String[] args){{//直接使用{}定义,普通方法块int x =10;System.out.println("x1 = "+x);}int x =100;System.out.println("x2 = "+x);}}
💙小结
🌟 5.内部类
💙什么是内部类
🔎在Java中,允许一个类的定义位于另一个类的内部,前者称为
内部类
,后者称为
外部类
Inner class
一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner class
的名字不能与包含它的外部类类名相同;
💙内部类分类
分类: 1️⃣
成员内部类
(static成员内部类和非static成员内部类)
2️⃣局部内部类
(不谈修饰符)
3️⃣匿名内部类
🌀成员内部类
💎成员内部类既可以作为类的成员的角色存在,也可以作为成员内部类作为类的角色存在:
❄️作为类的成员的角色
和外部类不同,
Inner class
还可以声明为
private
或
protected
;
1️⃣ 可以调用外部类的结构
2️⃣ Inner class 可以声明为static的, 但此时就不能再使用外层类的非static的成员变量
示例:
classOuter{privateint s;publicclassInner{publicvoidmb(){
s =100;System.out.println("在内部类Inner中s="+ s);}}publicvoidma(){Inner i =newInner();
i.mb();}}publicclassInnerTest{publicstaticvoidmain(String args[]){Outer o =newOuter();
o.ma();}}
❄️作为类的角色
可以在内部定义
属性
、
方法
、
构造器
等结构
1️⃣ 可以声明为abstract类 , 因此可以被其它的内部类继承
2️⃣ 可以声明为final的
3️⃣ 编译以后生成O u t e r C l a s s OuterClass OuterClassInnerClass.class$字节码文件( 也适用于局部内部类)
示例:
publicclassOuter{privateint s =111;publicclassInner{privateint s =222;publicvoidmb(int s){System.out.println(s);// 局部变量sSystem.out.println(this.s);// 内部类对象的属性sSystem.out.println(Outer.this.s);// 外部类对象属性s}}publicstaticvoidmain(String args[]){Outer a =newOuter();Outer.Inner b = a.newInner();
b.mb(333);}}
❗️注意
1️⃣. 非static的成员内部类中的成员不能声明为static的, 只有在外部类或static的成员内部类中才可声明static成员。
2️⃣. 外部类访问成员内部类的成员, 需要“内部类.成员”或“内部类对象.成员”的方式
3️⃣. 成员内部类可以直接使用外部类的所有成员, 包括私有的数据
4️⃣. 当想要在外部类的静态成员部分使用内部类时, 可以考虑内部类声明为静态的
🌀局部内部类
❄️声明局部内部类
class 外部类{
方法(){class 局部内部类{}}{class 局部内部类{}}}
❄️使用局部内部类
💎只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
❄️局部内部类的特点
1️⃣ 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但
是前面冠以外部类的类名和$符号,以及数字编号。
2️⃣只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方
都不能使用该类。
3️⃣ 局部内部类可以使用外部类的成员,包括私有的。
4️⃣ 局部内部类可以使用外部方法的局部变量,但是必须是final的。 由局部内部类和局
部变量的声明周期不同所致。
5️⃣ 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
6️⃣ 局部内部类不能使用static修饰,因此也不能包含静态成员
🌀匿名内部类
💎匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。
一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
❄️声明匿名内部类
new 父类构造器(实参列表) |实现接口(){//匿名内部类的类体部分}
❄️匿名内部类的特点
1️⃣ 匿名内部类必须继承父类或实现接口
2️⃣ 匿名内部类只能有一个对象
3️⃣ 匿名内部类对象只能使用多态形式引用
💙小结
本篇主要介绍类和类的成员,其中有部分会涉及到后面的继承,关键字等的知识,会在后续更新的博客中具体讲解,还请大家继续关注.
如果本篇文章中有错误的地方还请在评论区指出,感谢感谢
版权归原作者 摸鱼の文酱 所有, 如有侵权,请联系我们删除。