一:框架搭建
首先我们先把java代码的每一块部分的顺序,位置进行框架,比如类在哪里,main方法在哪里,成员变量又在哪里,构造方法又该写在哪等等,然后我们再一块一块的进行分析
一:最大的两个框架
首先,这是最大的两个框架(当然,它们都属于同一个包里面)
一般class 类名是我们自己编写的类,而public class 主类名则是每个java文件必备的一个类
二:class类和主类里面的框架
我们先解构class类
class类中往下分,整体分为三个部分:成员变量区,构造方法区,成员方法区
再解构主类
主类往下分,整体分为四个部分:成员变量区,构造方法区,main方法区,成员方法区(一般编写顺序如下,但也可以进行顺序上的调整)
三:分析每个小块的框架
1.class类里的成员变量区
当我们创建成员变量时,要么定义的时候就赋值,要么就不赋值,等着后面的构造方法或者成员方法来进行赋值。
接下来我们就要重点解释访问限定符:
访问限定符:
private , default(也就是变量前面什么都没写,系统默认给的访问限定符) , public
(protected因为牵扯到继承的父类和子类,在本篇只讲类和对象的原因下,就不讲了)
一:private:
该变量能使用的范围:同一个包的同一个类
用我们刚刚搭建的框架来表示,就在这一块范围内,private修饰的变量都能使用
也就是说,如果出了这个红色圈范围,那么这个private修饰的变量就不能用了
二:default
该变量能使用的范围:同一个包的不同类
用我们刚刚搭建的框架来表示,就在这一块范围内,default的变量都能使用
也就是说,如果出了这个红色圈的范围(即如果是其他包要使用default的变量),default变量就不能使用
三:public
该变量能使用的范围:不同包的不同类(人话:哪都能用)
用我们刚刚搭建的框架来表示,就在这一块范围内,public的变量都能使用
2.class类里的构造方法区
这里面就可以写各种各样的构造方法,有关构造方法的知识点总结如下
构造方法知识总结:
1.我们可以不写任何的构造方法,这时系统会默认帮我们写一个无参的构造方法,但是我们一旦自己写了任何一个构造方法,那么系统就不会帮我们写那个无参的构造方法
举个例子:我们不写时,有一个无参构造方法。然后我们写了一个带参的构造方法,这时我们拥有的构造方法只有这个带参的构造方法,无参的那个构造方法就消失了,所以如果我们需要无参的构造方法,我们必须自己给它补上
2.当我们写构造方法的时候,如果要写2个及以上的构造方法,那么这个时候就叫做构造方法的重载,这时我们要从传参的个数,传参的类型,以及传参的顺序来进行区分,如果出现所有都一模一样的话,就会报错
3.创建对象的时候,就会调用构造方法,即通过new来调用,例如 Animal dog=new Animal();
4.如果要在构造方法中调用其他构造方法,要用this(),并且this()这行代码必须放在构造方法的第一行
5.不能形成环,即A构造方法里面调用B构造方法,B构造方法里面又调用A构造方法
例如
class Animal{
//成员变量区
String name;
int age;
//构造方法区
public Animal(String name){ //带有一个参数的构造方法
this.name=name;
age=3;
}
public Animal(String newName,int age){ //带有两个参数的构造方法
this(newName); //用this进行构造方法里面调用其他的构造方法
this.age=age;
}
}
5.根据上面这段代码,我们也知道,如果当传入的形参和成员变量同名时,可以通过this.来表示这个是成员变量
3.class类里的成员方法区
这时候我们要注意了:我们之前定义的变量都叫成员变量,换个通俗一点的名字就是全局变量
而现在我们在方法里面定义的变量就叫局部变量了
局部变量与全局变量的不同点:
1.全局变量(成员变量)可以初始化也可以不初始化,就像我们刚刚上面写的一样,可以定义的时候就赋值,也可以定义的时候不赋值。但是局部变量必须进行初始化,即必须在定义的时候赋值,不然就会报错
2.生命周期不一样,局部变量只要当程序运行走出了方法,那么这个局部变量就会被销毁,相当于这个变量就不存在了,而成员变量只要通过类创建了对象,只要这个类的对象还在,那么这个成员变量还可以继续使用,也就是仍然存在
顺便提一嘴,如果用了static(静态)来修饰类,方法或者变量的话,那么简单理解就相当于永生了,即只要你还没关闭这个idea或者其他的编译器,它都可以使用
大致内存分布如下,本文就不细讲了
4.主类里的main方法区
主类的成员变量区和构造方法区与class类里面基本一样(因为都是类),就不再解构一遍了
封装:
就相当于main方法区是一个厨房,你要完成一道菜品(实现题目要求),要调用所需食材(调用各种类),调用所需调料(调用各种方法),而一般来说,食材都是拿塑料袋装着的,调料都是拿瓶子罐子装着的,这样子调用就会很方便,这种思想也就是封装
5.主类里的成员方法区
跟class类里的成员方法区基本一样
二:什么是类和对象
简单来说就是克隆
就像电影里面,克隆得先要有母体,而这个母体就相当于java里的类,这个母体必须要具备什么样的特性,就是由我们来决定的
比如我想克隆一堆学生,那么我们再设计母体(类)的时候,就要添加其特性:比如这个学生得要有名字,得要有年龄,得要有性别等等,把我们想要的特性加进去,不想要的特性就可以不加,
这时候母体设计好了,就可以开始克隆了,克隆出了的克隆体就相当于java里的对象,但是我们也想把每个克隆体作一些区分,比如像电影里代号克隆人一号,克隆人二号等等,就是在母体的基础上进行微调
结合我们上面搭建的框架,简单进行对应:
class类里的成员变量区——设计母体时加我们想要的特性(名词)
class类里的构造方法区——在母体的基础上进行微调(修改名词)
class类里的成员方法区——母体的具体能实现的动作和能力(动词)
举个例子:
这段代码就相当于我设计了一个狗的母体(这时dog就称作为类)
class dog {
//成员变量区
String name;
int age;
//构造方法区
public dog(String newName,int newAge){
this.name=newName;
this.age=age;
}
//成员方法区
public void eat(){
System.out.println("吃吃吃");
}
public void bark(){
System.out.println("汪汪汪");
}
}
这段代码就相当于我克隆了两条狗,并通过构造方法在母体的基础上进行了微调(此时g1,g2就称作为对象)
public class J54 {
public static void main(String[] args) {
dog g1=new dog("旺财",3);
dog g2=new dog("大黄",4);
}
}
这段代码就相当于我命令克隆的两条狗进行动作行为(通过对象.成员方法)
public class J54 {
public static void main(String[] args) {
dog g1=new dog("旺财",3);
dog g2=new dog("大黄",4);
g1.eat();
g1.bark();
g2.eat();
g2.bark();
}
}
三.代码块
在上面我们搭建的框架基础上,还会加入一些部分——代码块
代码块可分为这四部分:普通代码块,构造块,静态块,同步代码块(多线程部分再谈,这里就不介绍了)
1.普通代码块
作用:我们刚刚讲了局部变量和成员变量的生命周期,如果我们不想让它们的生命周期为默认的范围的话,我们就可以用普通代码块进行修改
public class J54 {
public static void main(String[] args) {
//普通代码块
{
int x=10;
System.out.println("x1="+x);
}
int x=100;
System.out.println("x2="+x);
}
}
也就是我们用{}里面的内容就叫做普通代码块,其中普通代码块里的x的生命周期就在出了{}后就销毁
2.构造代码块(也叫实例代码块)
作用:一般用于初始化实例成员变量
class Student{ //类
//成员变量区
private String name;
private String gender;
private int age;
private double score;
//构造方法区
public Student(){
System.out.println("我是无参构造方法");
}
//实例代码块
{
this.name="bit";
this.age=12;
this.score=100;
System.out.println("我是实例代码块");
}
//成员方法区
public void show(){
System.out.println("我是成员方法");
}
}
public class J54 { //主类
public static void main(String[] args) { //main方法区
Student stu=new Student(); //创建对象
stu.show(); //调用对象的方法
}
//主类里的成员方法区
public static void func(){
System.out.println("我是主类里的成员方法");
}
}
这段代码就是实例代码块的用途,同时也是我们上面搭建整体框架的一个完整样例
注意:实例代码块只有在创建对象时才会执行,类比我们说的克隆,就相当于如果我们在设计母体时对母体进行了修改(编写实例代码块),但我们不进行克隆(不创建对象),那么它永远只在母体上(只存在类里面),也就不会执行我们修改的任何地方(不会执行实例代码块)
3.静态代码块
作用:一般用于初始化静态成员变量
在将静态代码块之前,我们再简单讲一下静态,也就是static
什么是静态(static)
刚刚我们简单提到了被static修饰的,就相当于永生,同时内存分配也会专门分配到static静态区,这是我们表面知道的,但是其深层意义是——被static修饰的就不依赖于对象了,而是属于类,也就是大家可以共享了
我们还是用克隆来类比,刚刚实例代码块是必须在克隆的过程中才会被执行(创建对象时才执行),如果不克隆就不执行(不创建对象就不执行),而静态代码块相当于是母体直接活了,也就是说母体不再只是一个死的样本了,而能够像具有生命的生物体一样进行一切操作,同时与其他克隆体建立了链接,跟Java语言里面进行对应,大致如下:
通过对象修改静态成员变量的话,类中的值也会被修改——对克隆体进行特性上的改造,因为建立了链接,母体的特性也会跟着被改造
通过类 . 静态成员方法也可以直接使用——母体活了,母体自己执行其动作或能力
静态方法总结
1.不属于某个具体的对象,是类方法
2.可以通过对象调用(因为母体和克隆体建立了链接),也可以通过类名.静态方法名调用,但更推荐后者
3.不能在静态方法中访问任何非静态成员变量(因为没被静态的是不共享的,就相当于你说你要请客,但是又要掏别人钱包去买一部分单,不合理)
静态代码块
使用方法
static{
…………
}
花括号{}里面的就是静态代码块
举例:
class Student{ //类
//成员变量区
private String name;
private String gender;
private int age;
private double score;
private static int ID;
//构造方法区
public Student(){
System.out.println("我是无参构造方法");
}
//实例代码块
{
this.name="bit";
this.age=12;
this.score=100;
System.out.println("我是实例代码块");
}
//静态代码块
static{
ID=666;
System.out.println("我是静态代码块");
}
//成员方法区
public void show(){
System.out.println("我是成员方法");
}
}
public class J54 { //主类
public static void main(String[] args) { //main方法区
Student stu=new Student(); //创建对象
stu.show(); //调用对象的方法
}
//主类里的成员方法区
public static void func(){
System.out.println("我是主类里的成员方法");
}
}
可以看到,我们用静态代码块对ID这个静态成员变量进行了初始化
静态代码块总结
1.静态代码块不管生成多少个对象,其只会执行一次(因为只有母体这么一个,无论克隆多少个克隆体,母体也只有一个)
2.如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(相当于既对母体的头部进行了改造,腿部也进行了改造,按照先上后下,那么改造的顺序就是先头部再腿部)
四.打印对象
问题
我们看到一个对象,我们想知道它的所有信息,就想要把它的信息全部打印下来给我们看,但是如果直接打印对象,我们只能打印出它的地址
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) { //main方法区
Person person=new Person("jim","男",18); //创建对象
System.out.println(person); //打印对象
}
}
例如我们想打印jim,男,18这个对象,但是只会打印出这个对象的地址(也就是我们上面画的栈,堆,静态区内存图里面的栈中的引用变量的地址)
打印如下:
如果不理解的话,还是拿克隆来举例子,我们遇见了一个克隆体,我们想知道这一个克隆体的一切特性和能力,就像把它的资料打印出了,结果我们直接打印的话,只打印出了它的生产地址
那么我们该怎么办呢?
解决办法
重写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;
}
//主类的成员方法区
public String toString(){
return "["+name+","+gender+","+age+"]";
}
public static void main(String[] args) { //main方法区
Person person=new Person("jim","男",18); //创建对象
System.out.println(person); //打印对象
}
}
打印如下:
背后原因
简单来说,就是IDEA在编写System.out.println()这个方法时,又调用了其他方法来编写System.out.println(),其中有一个被调用的方法就是public String toString(),这个方法就是用来处理System.out.println()里如果接收到是对象名时,会打印这个对象的地址
于是我们直接重写了public String toString(),这样子System.out.println()遇见对象名时,则会调用我们自己写的public String toString(),系统的public String toString()就不被调用了
有关类和对象的知识基本讲的七七八八了,希望能通过这篇文章能将所有类和对象的知识点都串起来,把零散的知识点都组合起来