Java基础知识复习
1.类与对象中的内存分析
Person per=new Person();的理解
了解类与对象中的内存关系,首先从一个语句说起:Person per=new Person();通过一张图来进行理解
通过这张图我们课题理解到,new Person(),使用到了Person.class 文件,JVM会找到Person.class文件,并将其加载到内存中。在堆内存中开辟空间,并分配内配内存地址。在堆内存中建立对象的特有属性,并进行默认初始化。这里对name初始化为null(引用数据类型初始化时为空),age初始化为0(int初始化为0)。最后将内存中的地址赋给栈内存中的Per变量。这里per在栈中都还有一个地址没有给出来,用于对per的调用。这时初始化完成了。
如果把这条语句分为Person per =null; per=new Person();会变成下图所示内存结构:
注意:如果在没有对per new空间的情况下就调用per中的属性和方法时会出现空指向异常:nullPointerException。
注意:此时如果来一条语句Person per1=per;per1.age=10;那么由于per和per1都指向一个堆内存,这时per.age也等于10。
同样为引用类型的数组也是这样的:
java中的引用传递和值传递问题:https://www.cnblogs.com/xiaoxiaoyihan/p/4883770.html ,讲的很透彻,很容易理解。
java中垃圾的产生:
这段简单的代码便会产生垃圾,per1和per2都指向指定的堆内存,但是代码中per2指向了per1,于是per2中原来指向的堆数据则变成了垃圾数据,由GC定期回收。当然如果垃圾数据过多会使GC压力过大,使得程序性能降低。
匿名对象:new Person(“张三”,20).tostring;可以调用方法,当时由于此对象没有任何引用,所以调用之后会被GC回收。
2.this和static关键字的作用
this关键字调用本类对象和本类方法:这个很常见,比如构造函数中的this.name=name;以及调用本类方法,但这通常是简写。
this关键字调用本类构造函数:可以提高代码可重用率,减少重复代码,比如下面三个构造函数:
如果system.out.println是多行代码,那么代码重用性明显变高。
static关键字的作用:
- 用来修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享;
- 用来修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类;
- 静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键;其中静态代码块在主方法之前执行。
- 静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便。
static和不同static的区别:非static必须在实例化对象产生之后才可以使用,static可以在没有实例化对象产生的情况下直接通过类名称进行调用。并且static属性并不是存在堆之中,而是存在一个静态存储全局数据区之中。并且static修饰的类成员,在程序运行过程中,只需要初始化一次即可,不会进行多次的初始化。下面一张图是对于一个类中static属性和普通属性的存储内存分析:
深度好文:https://www.cnblogs.com/dotgua/p/6354151.html
问题:为什么static属性不能用this来指。
回答:因为this表示的当前的是当前对象,而使用static属性不需要实例化对象。
3.数组
可变参数传递:关于数组传递,在jdk1.5之后使用可变参数传递,实际上还是数组传递,不过更加灵活,接收类型是:int...names这种
https://blog.csdn.net/lxxiang1/article/details/82312799
对象数组:代码以及对应的内存结构
4.String(不可变性)
string对象常量池:string对象常量池分为静态常量池和运行时常量池,其中静态常量池是在类加载的时候将程序中的string存到string的常量池之中。
而运行时常量池是在类加载之后,可能会有一些变量,这时候提供的一个常量池。
值得注意的是如果为info加上final,那么final就会成为一个常量,结果则为true:
string变量的初始化的两种方式比较:
直接赋值:string s="mldn";对于直接赋值,只会产生一个实例化对象,首先查看string池中是否有和初始化字符相同的字符,如果有那么则直接把字符池中mldn的引用指向变量,如果没有那么则在字符池中开辟新的空间存储。
构造方法:string s=new string("mldn");会产生两个实例化对象,不会自动入池,无法实现对象重用。可以用intern手工入池。这个语句中首先对“mldn”进行匿名对象创建,这是会在string池中进行查找,如果没有则初始化一个,这就是第一个实例化(这个对象在string池中,作用是传递参数以便于new在栈中开辟空间),然后是new关键字,这是不会在string池中查找,而是在栈中(实际上string池也是一个特殊的栈)中开辟新空间存储。这是第二个实例化对象(在栈中)。
1.jdk7之前是常量池是在方法区(永久代)中,之后则移到了堆中。
2.String a = "abc"//这里的abc 是显式字符串常量,存在于常量池里
3.String a =new String("abc");//这里的abc是常量,存在于常量池,而new String(“abc”)是对象存在于堆中.
深度好文:http://blog.sina.com.cn/s/blog_6a6b14100100zn6r.html
但是对于string的运算是不相等的:
string设计成不可变的原因:
多线程安全性
类加载中体现的安全性
使用常量池节省空间
https://blog.csdn.net/jiahao1186/article/details/81150912
string修改引起的大量垃圾:由于string对象值具有不可变性,所以在一些情况下的操作
这样就会形成垃圾,假如在一个1000次的for循环中修改str,那么就会形成1000个垃圾,不利于程序性能。所以应该尽量减少这种操作。其实可以使用stringbuilder完成。
其他:
字符串转换成字节:str.getbytes();
字符串之间的比较:equals和equalsignorecase,equalsignorecase不区分大小写。还有compareTo和compareignorecase。compare的用法是比较两个字符串的大小,可以看到首先是比较第一个字符,如果一样大再比较第二个。字符比较是用字符所对应的int数大小。
String常用方法:https://www.cnblogs.com/aidian/p/8805540.html
对于int和integer:
int是基本数据类型, Integer是对象是int的包装类。
基本数据类型存储局部变量存储在栈中,全局变量存储在堆中
(只分为栈和堆理解是可以的,但学的会头大)
(jdk8之前堆里还有方法区具体在方法区里(现在方法区独立不算堆))
按照javase8虚拟机规范并没有提到基本数据类型在栈中。
栈中只会存储类的实例化引用,和局部变量。
integer是final类 终态类存储在常量池(常量池在方法区里)
常量池中的数据有就引用,没有就创建
Integer i=10;
Integer f=10;
常量池中已有10这个数,不需要在创建引用这个10的地址即可。
5.继承和多态
继承:
如果定义了一个父类和一个子类,实例化对象时内存图:
实例化子类对象一定会实例化父类对象,并且父类构造方法执行先于子类,对于方法的覆写实行就近查找原则,如果子类需要调用已经经过子类覆写过的父类方法,那么需要使用super关键字。注意:子类覆写不能比父类拥有更严格的权限。父类中的私有属性和方法不能被覆写,如果子类覆写父类中的私有方法和属性实际上是创建了新的方法和属性。
面试题:super和this区别 https://blog.csdn.net/weixin_40995778/article/details/79771513
多态:
向上转型:解决接收或返回参数的统一性
其中databasemessage和webservermessage继承于message类。
方法调用问题:https://www.cnblogs.com/buptldf/p/4959480.html
6.final关键字的基本用法以及细节介绍
基本用法:修饰类,修饰成员变量,修饰方法