类的初始化和实例化的区别
类的初始化:是完成程序执行前的准备工作。在这个阶段,静态的(变量,方法,代码块)会被执行。同时在会开辟一块存储空间用来存放静态的数据。初始化只在类加载的时候执行一次。
类的实例化:是指创建一个对象的过程。这个过程中会在堆中开辟内存,将一些非静态的方法,变量存放在里面。在程序执行的过程中,可以创建多个对象,既多次实例化。每次实例化都会开辟一块新的内存。
比如说我们以洗衣服为例:
1)假设此时我们要洗一件衣服,我们如果说要是面向过程的话,那么就是
第一步:拿一个盆子
第二步:放水
第三步:放衣服
第四步:放洗衣粉
第五步:手搓
第六步:换水
第七步:拧干
第八步:晒衣服
那么整个洗衣服的过程就是:人把衣服放进洗衣机,倒入洗衣粉,启动洗衣机,洗衣机就会完成整个洗衣服的过程并且会甩干
如果说以面向对象的思想来进行凯带着一件事情的话:
在这个洗衣服的过程中,我们需要用到四个对象,人,衣服,洗衣粉,洗衣机,整个过程是靠人,衣服,洗衣粉,洗衣机四个对象进行相互交互来进行完成这个过程的,人这个对象是不需要关心洗衣机是如何进行洗衣服,如何进行甩干的
面向对象和面向过程:
1)C语言是面向过程的,关注的是过程,分析出解决问题的步骤,通过函数调用来进行逐步解决问题
2)但是Java是面向对象的,关注的是对象,将同一个事情拆分成不同的对象,靠对象之间来相互配合进行完成一件事情今年
3)面向过程注重的是过程,也就是参与过程中所有所涉及到的行为,就是功能,但是面向对象注重的是对象,也就是说参与过程所涉及到的主体,通过逻辑将一个个的功能连接起来
4)面向对象:打开冰箱门,把大象进行存储进去储存,关闭冰箱门都是对冰箱进行的操作,这是对冰箱的一种行为;但是冰箱就是一个对象,所以只要冰箱所具备的功能,就都需要被定义到冰箱中;
5)面向对象是思考问题的一种方式,是一种思想,面向对象设计有一个重要的经验:谁拥有这些数据,谁就对外提供操作这些数据(私有的方法),被动的一方是数据的拥有者,主动的一方是执行者
6)类就是一类对象的统称,对象就是这一类具体化的一个实例,通过一个类可以实例化多个对象,实例化出来的对象,占用实际的物理空间,存储类成员变量Java是一种纯面向对象的语言,面向对象是解决问题的一种重要思想,主要是依赖对象之间的交互来完成一件事情
注意:在对象里面是不存在方法的,方法是不占内存的,只有说调用了方法,才会在栈上面开辟内存
一:成员变量(属性字段):定义在方法外的但是类内的字段和属性,分为普通成员变量和静态成员变量:
普通成员变量:引用.字段,所以说是依靠对象的引用来进行访问的,如果我们的成员变量没有赋初值,那么访问的时候打印的就是默认值,但是局部变量在初始化的时候一定要进行赋值,否则再初始化的时候,程序会发生报错,每一个对象都有自己的默认的成员变量,我们所有的代码片段都在方法区里面
咱们的成员变量没有进行初始化的时候,默认值就是对应的初始值
普通的成员变量是属于对象的
整形:byte,short,int,long默认值是0 字符型:double,float默认是0.0 布尔类型:boolean:默认是false 引用数据类型:数组,接口他们的默认值都是空 字符类型:char--->/u000000
静态成员变量:引用.字段或者是类名.字段,叫做类变量,静态成员变量也在方法区里面,实质上不需要对象的引用来进行访问
class Student{ public String name; public int age;//这是一个普通成员变量 public static int count=9;//这是一个静态成员变量 public void run() { System.out.println(1); } public static void start() { System.out.println(2); } } new Student()在堆上,但是指向new Student()的实例(引用)在栈上;
注意:上面的person是一个变量,不是地址,只不过这个变量,里面存放的是地址,这个变量也叫做引用,这个变量类型就是Person类型
二:成员方法--->行为
普通成员方法和静态成员方法,方法的这些片段在咱们的方法区里面,我们只要调用这个方法,在栈上面就要为这个方法开辟内存;
静态成员方法也是依据类名.方法名来进行访问
注意:在我们普通的方法内部,是不可以定义静态的变量
1)static修饰的变量是属于类变量,是在方法区里面,而方法是属于对象的,静态成员变量赋值的时候通过
类名.变量=具体的值
2)普通成员方法调用,需要对象的引用来进行访问,如果可以定义static,就可以通过类名来进行访问,而成员方法调用还需要new一个对象呢
3)在我们静态成员方法里面也是不可以进行定义static类型的变量,因为static类型的变量是属于类的,如果static定义的变量在方法里面,这就是属于方法的,这也是不可以的,总结:静态的成员变量是不可以在方法中定义的
4)在普通方法内部是可以调用静态方法的,但是在静态方法里面是不可以调用普通方法的,所以静态方法里面只能调静态方法,如果实在想要在静态方法里面调用普通的方法,那就需要在静态方法里面new对象,再通过这个对象去访问这个普通的方法
在静态方法里面不可以访问普通的成员变量和方法,也就是不能直接访问非静态的数据成员和成员方法,也不可以使用this和super关键字来进行访问成员变量和成员方法
5)一个引用不可以同时指向多个对象,引用不一定是在栈上面,也可以在堆上面
6)我们在一个类中的普通的方法可以通过this.静态成员变量来进行访问这个变量,也是可以通过类名.变量来进行访问
7)static修饰的类变量的生命周期伴随着类的一生,随着类的加载进行创建,随着类的卸载而进行销毁
package Demo; class Person{ public String name; public int age; } public class TestDemo { Person person=new Person();//在堆上面 public static void main(String[] args) { TestDemo testDemo=new TestDemo(); } }
上面的这些引用全部在JAVA虚拟机栈
static修饰的关键字的作用:
1)被static修饰的成员变量和成员方法独立于该类的任何对象,他是和类紧紧联系在一起的
被类所有的实例所共享,他是永远在方法区的,它不属于类的对象,但是属于类;
2)这也就是说不管创建多少对象,static修饰的变量只占有一块内存。3)被static修饰的方法称之为静态成员方法,静态方法属于类,而不属于类的对象,静态方法可以访问静态数据成员,并且可以更改静态数据成员的值,但是不可以定义一个静态成员变量,所以说静态成员通常是通过静态方法来进行访问的
4)Java中,被static修饰的 class 都是 内部类,static class 是可以被继承的,但是被static修饰的方法是不可以重写的
5)内部类就是定义到类内部的类:
我们再给内部类加上static关键字之后,当前创建内部类的实例就不会依托于外部类的实例
如果我们不给内部类加上static就必须先把外部类的实例进行创建出来,在进行创建内部类的实例
1)静态方法和实例没有关系,而是和类相关,静态方法不能直接访问非静态数据成员和普通成员方法;
2)this和super两个关键字是不可以在静态上下文进行使用,因为this是当前对象的引用,super是当前父类实例的引用;
3)这个变量放在哪里和是否被final修饰没有什么关系
下面我们来进行讲解一下类的初始化顺序:
1.普通类(这里面是没有继承关系的)
一:静态部分:
1)静态部分(静态变量,常量,静态代码块)
2)在我们的类加载阶段,类中存在多个静态部分,会按照顺序进行执行
3)静态代码块只会执行一次,况且静态的变量,常量只会创建一份
二:非静态部分:(实例变量,常量,实例代码块)
当我们有对象创建的时候才会执行,按顺序执行
三:我们最后会执行构造方法,当有对象创建的时候才会执行
2.派生类的初始化顺序:
一:静态部分(静态变量,常量,静态代码块)
1)父类静态代码块会优于子类的静态代码块执行,况且最早执行
2)只有当我们的第一次进行实例化子类对象的时候,父类和子类的静态部分才会执行
3)父类非静态部分(实例变量,常量,实例代码块和父类的构造方法)
4)子类非静态部分(实例变量,常量,实例代码块和子类的构造方法)
重写ToString方法:println会默认调用父类的ToString
1)public void println(Object x) { String s = String.valueOf(x); synchronized (this) { print(s); newLine(); } } 2)public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); } 3) public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
如果不加上this,那么就会有局部变量优先使用的原则
封装:
1)是将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅仅对外提供接口来和对象进行交互
2)我们通常把成员变量设置成private,成员方法设置成public,我们对类的内部的实现细节进行了隐藏和封装,我们对外只能提供一些公开的方法供其他用户来进行访问,没有必要的属性不用公开在类外
3)不必要的公开里面的数据成员或方法,使用private进行修饰,为了更安全,它会提供公有的方法,对于类的调用者来说,不需要知道具体的实现细节,只需要调用这些共有的方法即可,降低了代码的管理复杂度
4)这就类似于说对于电脑这样一个复杂的设备,我们给用户提供的只有开关机,通过键盘进行输入,显示器,USB插孔,让我们的用户与计算机完成交互;
5)但是我们实际上,电脑真正的工作就是CPU显卡,还有一些硬件;用户只需要知道,怎么开机,怎么通过键盘和鼠标与用户进行交互就可以了,而不需要知道CPU内部是如何进行设计的,主板上面线路是怎么布局的;因此我们的计算机厂商进行出厂的时候,可以将内部的实现细节隐藏起来,仅仅对外提供开关机,鼠标和插口,让用户和计算机实现交互
一:构造方法:实例化对象的时候,一定会调用构造方法,当我们的构造方法调用完成之后,对象真正的产生了
是一个特殊的成员方法,他的方法名称和类名是相同的,而且没有返回值,在我们进行创建实例化对象的时候,由我们的编译器自动进行调用,并且在整个对象的生命周期里面只进行调用一次,况且可以提供不同版本的构造方法
我们的构造方法的作用就是给对象中的成员进行初始化,但是并不会负责给对象开辟空间
可以这么说,当我们的构造方法调用完成之后,咱们的对象实际上才产生了,对象的产生一定是要进行调用构造方法
1)每一个类中至少存在一个构造方法,当你没有提供任何构造方法的时候,编译器会自动提供一个不带有参数的构造方法,在构造方法中,我们可以通过this来进行调用其他构造方法来进行简化代码
2)当你提供了构造方法,编译器就不会再生成构造方法了
3)构造方法之间是可以构成重载
4)我们可以在无参的构造方法中调用具有两个参数的构造方法,我们通过this()调用其他的构造方法的时候,必须是放在构造方法里面,而且必须是第一行
4)注意:
1)我们在构造方法里面,我们通过this(....)去调用其他构造方法的时候,我们的这条语句必须是构造方法中的第一条语句
2)我们的多个构造方法之间不可以进行相互调用,我掉你,你调用我,不能循环调用,不能形成环class Person{ public String name; public int age; public Person(String name) { this(90); System.out.println(1); } public Person(int age){ this("abc"); } }
1)我们在继承的基础上面,子类对象在进行构造的时候,需要先进行调用基类的构造方法,然后再去执行子类的构造方法
2)我们在子类的构造方法里面,我们虽然并没有写有关于基类构造的代码,但是当我们在构建子类对象的时候,先执行基类的构造方法,然后再去执行子类的构造方法
3)我们的原因在于,子类对象中成员是由两部分组成的,基类继承下来的和子类新增加的部分,父类和子类,肯定是现有父再有子,所以我们在进行构建子类对象的时候·,我们的子类对象肯定要先调用基类的构造方法,将我们的基类的继承下来的成员进行构造完整,然后再进行完成子类自己的构造,再将子类的新增加的成员初始化完整
一:如果说我们的父类显示无参或者默认的构造方法,在我们子类的构造方法的第一行默认会含有隐含的super()调用,即调用基类的构造方法:
static class Father{ public Father() { System.out.println("我是父类的构造方法"); } } static class Child extends Father{ public Child() { super(); //注意:在我们的子类的构造方法里面会默认调用基类的无参构造方法,super(),当我们的用户没有写的时候,编译器会自动进行添加的,况且super()必须是子类构造方法中的第一条语句 System.out.println("我是子类的构造方法"); } } public static void main(String[] args) { Child child=new Child(); }
二:如果父类构造方法是含有参数的,那么我们需要用户显式定义构造方法,用super()的时候,必须出现在第一条语句
this访问成员变量:this.data;
this访问成员方法:this.func();
this访问构造方法:this();
一个对象的产生(new的过程),要经过几步?
1)为对象分配合适的内存空间
2)调用合适的构造方法(可能有多个构造方法)
class Student{ public String username; public String password; public int age; public void SetData(String name,String word,int IntAge){ username=name; word=word; age=IntAge; } public void run(){ System.out.println(username); System.out.println(password); System.out.println(age); } public void start(){ this.run(); } } public class Solution{ public static void main(String[] args) { Student student1=new Student(); Student student2=new Student(); Student student3=new Student(); student1.SetData("李佳伟","张三",10); student2.SetData("周云刚","王五",20); student3.SetData("霍飞跃","90",30); student1.run(); student2.run(); student3.run(); } }
这两个方法如何知道他们打印的是哪一个对象?他们进行设置的是哪一个对象?
1)谁进行调用这个方法,设置的就是哪一个对象
2)每一个方法的第一个参数都默认了一个隐藏对象:类的名字 this,谁调用这个方法谁就是this
this关键字的用法:
在我们的成员方法当中每一个函数的前面有一个默认的参数(类名 this),谁调用当前的这个方法,谁就是this
class Student{ public String username; public String password; public int age; public Student(){ this("我是李家伟","今年18岁");//必须放在构造方法里面,况且必须是第一行,在构造方法里面调用其他的构造方法 System.out.println("我是带有两个参数的构造方法"); } public Student(String username,String password){ this.username=username; this.password=password; } } public class Solution{ public static void main(String[] args) { Student student1=new Student(); Student student2=new Student(); Student student3=new Student(); } }
class Solution{ public void run(Solution this){ } }
定义:我们的this引用是成员方法的参数之一,不需要用户进行传递实现,是由我们的编译器来进行自动完成,也就是说当前这个参数用户是看不到的,但是用户可以使用这个参数,况且this只能在成员方法中进行使用
1)this()调用自己的构造方法,使用放在第一行,况且只能在构造方法中适用,不能在其他方法中使用
2)this.data调用自己的属性,如果不加this,那么编译器就会认为局部变量优先,无法通过构造方法来对成员变量进行赋值
3)this.func()调用当前对象的方法
解决的方法就是当我们的方法形参名和我们的成员变量名相同,尤其是在我们的构造方法里面,形参名和我们的类的字段名相同的时候,也就是构造方法的形参名和成员变量的名字重复了之后,我们就可以用到this引用了
我们的this引用指向当前对象(成员方法运行的时候调用该成员方法的对象)
在成员方法中所有对成员变量的操作,都是通过该引用去访问
this是成员方法中第一个隐藏的参数,编译器会自动进行传递,在成员方法执行的时候,编译器会负责将调用成员方法的引用传递给该成员方法,由this来负责进行接收
当我们进行new关键字进行操作的时候, 虽然在程序方面只是一条简单的语句,但是在JVM层面还是要做很多事情的:
1)检测对象对应的类是否加载了,如果说没有进行加载,那么直接进行类加载
2)为对象分配内存空间
3)处理并发安全问题,比如说多个线程同时申请对象,JVM要进行保证对象分配的空间不冲突
4)初始化所进行分配的空间,就是对象空间被申请好了之后,对象中的成员已经被设置好了初始值
5)设置对象头信息
6)调用构造方法,给对象中的各个成员赋值
封装的主要意义就是说对外隐藏内部类的实现细节,增强程序的安全性
做题把循环输入写上