最近真的是状态太差了,可以说是很懒了,距离上次写博客竟然过了一个星期。昨天去huaxin去面试,他们那也主要找培训的,一进去全是我这么大的,顿时心情不太美妙,还好面试我的不是让我培训。。。。。不过从一点断断续续4点才从那出来,属实有点过分啊。对了,软件公司虽然有竞争关系,但是他们都有联系!!!!!他们都互相认识!!!
行了,我就不费话了,嘻嘻嘻,下面就是我要说的内容。
一.this和super
我们都知道,this指向本类,super指向父类,但是他们到底是什么?之前我知道this相当于是指向当前对象本身,但是既然是对象,那么能直接输出打印出地址吗?我做了一个小Demo。
package com.java.text;
public class TextThisAndSuper {
public static void main(String[] args) {
B1 b=new B1();
b.b_text();
// b.a_text();
}
}
class A1{
String a_name="A";
String a_age="18";
static int count=19;
public static void a_text() {
System.out.println("111111111");
}
}
class B1 extends A1{
String b_name="B";
String b_age="5";
public void b_text() {
//System.out.println(b_name+","+b_age+","+count+"a_name");
//this.a_age="111111"; (B1 this=new B1();? 我们可以想象这个对象是JVM自动给我们创建的,当你类存在时,这个对象就已经存在了,不管你用不用,它就在这里。----自己理解)
//System.out.println(this+"----"+this.a_age);
//B1 b2=new B1();
//b2.b_name="BB";
//System.out.println(b2+"-----"+b2.b_name);
//System.out.println(this+"----"+this.b_name);
A1 a1=new A1();
a1.a_age="qiao";
System.out.println(a1.a_age);
System.out.println(super.a_age);
System.out.println(a1);
System.out.println(super.getClass());
}
}
/*子类会继承父类的属性(拥有访问权限的),并且当子类中有和父类同名的属性时,子类的属性
*会将父类中的属性覆盖。静态方法和静态属性都能够被继承,但是静态方法不能够被重写,静态
*属性时可以被重写的(因为当子类没有同名属性时,会输出父类中的属性值,当子类中有同名属
*性时,会输出子类的属性值)。
* */
/*this是什么?其实this就是这个this所在类,也就是当前类的对象!我们通过输出this,可以看到
*com.java.text.B1@70dea4e,这明显就是一个B1类型的对象地址。
*我们知道子类可以继承父类的属性和方法(允许被继承的),所以this对象也会拥有父类中的属性和方法
*this上实际就是一个对象,它与其他的对象互不影响,他们有不同的内存地址,所以在我们创建一个其他
*对象后,更改这个对象的属性值,并不会对this对象有任何的影响。
* */
/*super是什么?我们也可以认为它是一个对象,是一个父类的对象,只不过不允许打印地址。这是和this
*对象不同的。
* */
在这个小demo中,我们还可以得出一些关于继承的结论:子类会继承父类的属性(拥有访问权限的),并且当子类中有和父类同名的属性时,子类的属性会将父类中的属性覆盖。静态方法和静态属性都能够被继承,但是静态方法不能够被重写,静态属性时可以被重写的(因为当子类没有同名属性时,会输出父类中的属性值,当子类中有同名属性时,会输出子类的属性值)。
但是上面的结论很早就知道,这不是我们想要的,所以,在这也得出了关于this的结论:其实this就是这个this所在类,也就是当前类的对象!我们通过输出this,可以看到com.java.text.B1@70dea4e,这明显就是一个B1类型的对象地址。 我们知道子类可以继承父类的属性和方法(允许被继承的),所以this对象也会拥有父类中的属性和方法this上实际就是一个对象,它与其他的对象互不影响,他们有不同的内存地址,所以在我们创建一个其他对象后,更改这个对象的属性值,并不会对this对象有任何的影响。
那么super又是怎么一回事?我们也可以认为它是一个对象,是一个父类的对象,只不过不允许打印地址。因为我们可以直接System.out.println(this),而不可以System.out.println(super)。
其实对于this,我们可以想象这个对象是JVM自动给我们创建的,当你类存在时,这个对象就已经存在了,不管你用不用,它就在这里。B1 this=new B1(); ----自己理解) ,但是super却不能直接打印,我也不知道应该怎么理解好。?????
二."=="和equals()方法
可以说这个问题是很多面试要考的,区别也很简单,这里我就先码一下。这里我也做了一个小Demo,通过这个Demo还看到一个关于常量池的问题,常量池的问题,一会我会说。
我们先来看这个Demo。
package com.java.text;
public class TextEquals {
public static void main(String[] args) {
TextEquals textEquals=new TextEquals();
textEquals.text4();
}
public void text1() {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2){
System.out.println("s1 == s2");
//说明引用s1和s2引用了同一个Monday对象。
}
else{
System.out.println("s1 != s2");
}
}
public void text2() {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2){
System.out.println("s1 == s2");
}
else{
System.out.println("s1 != s2");
}
if (s1.equals(s2)){
System.out.println("s1 equals s2");
//输出的不是地址,而是值
System.out.println(s1+","+s2);
}
else{
System.out.println("s1 not equals s2");
}
/*
* s1 != s2
s1 equals s2
*/
}
public void text3() {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2){
System.out.println("s1 == s2");
}
else {
System.out.println("s1 != s2");
}
if (s1.equals(s2)) {
System.out.println("s1 equals s2");
}
else{
System.out.println("s1 not equals s2");
}
/*
* s1 == s2
s1 equals s2
*/
}
public void text4() {
String a="qiao";
String b="qiao";
String c=new String("yaya");
String d=new String("yaya");
System.out.println(a==b);
System.out.println(c==d);
/*
* true
false
*/
}
}
/*java中数据类型,可以分为两种:一种是基本数据类型,也叫原始数据类型。byte,char,short,int,long,float,double,boolean
*8种。他们如果用“==”进行比较,则比较的是他们的值。
*第二种是引用数据类型,也叫符合数据类型。当他们用“==”进行比较的时候,比较的是他们在内存中的内存地址(因为他们是对象)。
*java当中所有的类都是继承Object的,Object是所有类的父类(基类)。在Object类中,定义了一个equals方法,这个
*方法的初始行为是比较两个对象的内存地址。但是这个方法在一些类库中别重写了,例如String,Integer,Date,他们都有
*自己的实现,而不是比较类在堆内存中的地址了。
*对于引用数据类型,之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置
*的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
* */
/*字符串缓冲池:程序在运行的时候会创建一个字符串缓冲池,当使用 s1 = "Monday" 这样的表达式创建字符串的时候,程序首
*先会在这个String(字符串)缓冲池中寻找相同值的对象(注意是表达式创建的时候,才去字符串缓冲池中去找)。在第一个程序
*中,s1先被放到了池中,所以在s2被创建的时候,程序找到了具有相同值的 s1,将s2引用s1所引用的对象"Monday"。所以s1
*和s2指向的是同一个对象,地址也就相同了。
*而第二种情况,则是通过new 操作符来创建的,所以新创建的对象是新的对象,该对象被创建在堆内存中,一个在缓冲池中,一个在
*堆内存中,所以这两个对象的内存地址是不同的。
*
*总的来说就是:通过表达式创建的字符串会被方到字符串缓冲池中,通过new 操作符创建的字符串对象会被放到堆内存中。
* */
/*java.lang.String的intern方法:intern()方法,例如:"abc".intern()方法的返回值还是字符串"abc",表
*面上看起来好像这个方 法没什么用处。但实际上,它做了个小动作:检查字符串缓冲池里是否存在"abc"这么一个字符串,如果存在,
*就返回池里的字符串;如果不存在,该方法会 把"abc"添加到字符串缓冲池中,然后再返回它的引用。
* */
在text1()方法中,我们通过表达式来创建了“两个”对象,我们用"=="和equals()方法分别对这两个引用进行比较,发现s1 == s2。我们都知道,java中数据类型,可以分为两种:一种是基本数据类型,也叫原始数据类型。有byte,char,short,int,long,float,double,boolean8种。他们(基本数据类型)如果用“==”进行比较,则比较的是他们的值。第二种是引用数据类型,也叫复合数据类型。当他们(引用数据类型)用“==”进行比较的时候,比较的是他们在内存中(堆内存中)的内存地址(因为他们是对象)。java当中所有的类都是继承Object的,Object是所有类的父类(基类)。在Object类中,定义了一个equals方法,这个方法的初始行为是比较两个对象的内存地址。但是这个方法在一些类库中别重写了,例如String,Integer,Date,他们都有自己的实现,而不是比较类在堆内存中的地址了。对于引用数据类型,之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,在重写后,equals()方法比较的是引用数据类型的值,而不是地址了。
由于“==”比较的是引用数据类型的地址,所以说明在text1()方法中两个对象引用都指向一个对象"Monday"。这是因为字符串缓冲池:程序在运行的时候会创建一个字符串缓冲池,当使用 s1 = "Monday" 这样的表达式创建字符串的时候,程序首先会在这个String(字符串)缓冲池中寻找相同值的对象(注意是表达式创建的时候,才去字符串缓冲池中去找)。在第一个程序中,s1先被放到了池中,所以在s2被创建的时候,程序找到了具有相同值的 s1,将s2引用s1所引用的对象"Monday"。所以s1和s2指向的是同一个对象,地址也就相同了。而第二种情况,则是通过new 操作符来创建的,所以新创建的对象是新的对象,该对象被创建在堆内存中,一个在缓冲池中,一个在堆内存中,所以这两个对象的内存地址是不同的。总的来说就是:通过表达式创建的字符串会被放到字符串缓冲池中,当通过表达式创建相同的对象时,就使引用指向这个对象。而通过new 操作符创建的字符串对象会被放到堆内存中。
这里还要介绍一个方法:java.lang.String的intern方法:intern()方法,例如:"abc".intern()方法的返回值还是字符串"abc",表面上看起来好像这个方 法没什么用处。但实际上,它做了个小动作:检查字符串缓冲池里是否存在"abc"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会 把"abc"添加到字符串缓冲池中,然后再返回它的引用。
三.常量池
我也不说什么是常量池,存在于那个地方,因为我不太懂。今天老师说对于Integer类型,常量池中只有-128到127,这区间的数字会在常量池中,而不再这个范围的数字会在堆内存中。我不知道对不对,所以做了个小Demo。
package com.java.text;
public class TextThisAndSuper {
public static void main(String[] args) {
TextThisAndSuper text=new TextThisAndSuper();
//text.text1();
//text.text2();
//text.text3();
text.text5();
}
public void text1() {
//先通过表达式创建,后通过new操作符来创建。
Integer a=10;
Integer b=10;
System.out.println(a==b); //true
Integer c=new Integer(10);
Integer d=new Integer(10);
System.out.println(c==d); //false
System.out.println(a==c); //false
}
public void text2() {
//先通过new操作符来创建,后通过表达式来创建。
Integer a=new Integer(10);
Integer b=10;
System.out.println(a==b); //false
}
public void text3() {
//超出边界范围,用表达式创建
Integer a=255;
Integer b=255;
Integer c=255;
System.out.println(a==b); //false
System.out.println(c==b); //false
System.out.println(c==a); //false
}
public void text4() {
//超出边界范围,先用new操作符来创建
Integer a=new Integer(255);
Integer b=255;
Integer c=255;
System.out.println(a==b); //false
System.out.println(b==c); //false
System.out.println(a==c); //false
}
public void text5() {
//在传参的时候进行比较
System.out.println(new Integer(255)==255); //true
System.out.println(255==new Integer(255)); //true
}
}
这个,不好意思,这个Demo和我预期的不太一样,我解释不了这种情况,明天我问问在来回答这个!
四.Map集合的key
Map集合的key可以重复吗,如果不可以重复那么是将值覆盖吗?键可以为空吗?值可以为空吗?键值可以同时为空吗?如果可以,可以通过key为null来取出对应的value吗?
package com.java.text;
import java.util.HashMap;
import java.util.Map;
public class TextMap {
public static void main(String[] args) {
Map map=new HashMap();
map.put("one", "one");
System.out.println(map); //{one=one}
//当键存在时,对键进行操作,会进行值的覆盖。
map.put("one", "two");
System.out.println(map); //{one=two}
map.put("one", null);
System.out.println(map); //{one=null}
map.put(null, null);
System.out.println(map); //{null=null, one=null}
System.out.println(map);
//通过null键取出值,可以通过null来获取对应的值
System.out.println(map.get(null)); //null
map.put(null, "four");
System.out.println(map.get(null)); //four
}
}
得出结论:当键存在时,在次向map集合中存放以存在key,会将key对应的值进行覆盖。键可以为空,值可以为空,键值可以同时为空,可以通过key为null来取出对应的value值。
五.泛型的意义
泛型的意义:类型(数据类型)的参数化,就是可以把类型像方法的参数那样传递。这一点意义非凡。
package com.java.text;
import java.util.ArrayList;
import java.util.List;
public class TextGenerics {
public static void main(String[] args) {
TextGenerics generics=new TextGenerics();
generics.text2();
}
public void text1() {
//验证一下不适用泛型的缺点
AAA a=new AAA();
a.setStr("1234");
List list=new ArrayList();
list.add(a);
//java.lang.String cannot be cast to java.lang.Integer
Integer str_int=(Integer)(((AAA)list.get(0)).getStr());
//原本就是String类型,所以可以变为String类型
String str_str=(String)(((AAA)list.get(0)).getStr());
System.out.println(str_int);
System.out.println(str_str);
}
public void text2() {
List list=new ArrayList();
BBB b=new BBB();
//不指明泛型 T 那么T就代表Object类型的。
b.setT("4321");
list.add(b);
//可以将Object类型变为String类型
String str=(String)((BBB)list.get(0)).getT();
System.out.println(str);
BBB<String> b2=new BBB<String>();
//指明了参数类型为String,传入其他的类型会报错。
b2.setT("1234");
}
public void text3() {
//给集合定义泛型,说明这个集合只能装在这个类型的元素
List<String> list=new ArrayList();
list.add("1");
}
}
class AAA{
//多态,父类引用接收子类对象,实际上的str类型仍然是String类型的。
private Object str;
public Object getStr() {
return str;
}
public void setStr(Object str) {
this.str = str;
}
}
class BBB<T>{
//这里的 T 是一种数据类型,通过初始化类的时候,指明参数的类型。
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
/*泛型的意义:类型(数据类型)的参数化,就是可以把类型像方法的参数那样传递。这一点意义非凡。
* */
这是自己写的一个Demo,只得出如果不使用泛型,那么会出现编译通过,而运行不通过的情况。这里贴一个链接,讲泛型的:https://www.cnblogs.com/lwbqqyumidi/p/3837629.html