分享

Java语言基础

 孤独一兵 2016-11-06

一、OOP(Object-oriented Programming)面向对象程序编程

初谈类和对象,所谓万物皆对象,类和对象有什么区别和联系?

类,是对某一种类型的定义,比如字符串,动物,人,飞机等等,而对象是指具体的字符串,动物,人...

如:猪是类,定义了,猪,有体重,有年龄,可以吃饭,可以睡觉,而对象是这只猪,那只猪,或者某只猪起个名字,叫小白,那么这种具体的猪,就是对象,而小白这个名字,则称为对象的引用,因为通过小白,我们可以找到指定的那头猪。

package com.yq;public class Pig { private int height; private int age; void eat() {

System.out.println('eat()');

} void sleep() {

System.out.println('sleep()');

} public String toString() { return getClass().getName() + '===@===' + Integer.toHexString(hashCode());

}// public String toString() {// return getClass().getName() + '@' + Integer.toHexString(hashCode());// }

public static void main(String[] args) {

Pig xiaoBai = new Pig();

Pig xiaoHei = new Pig();

xiaoBai.eat();

xiaoHei.sleep();

System.out.println(xiaoBai);

System.out.println(xiaoHei);

System.out.println('xiaoBai==xiaoHei?' + (xiaoBai == xiaoHei));

System.out.println(xiaoBai.getClass());

System.out.println(xiaoHei.getClass());

System.out.println('xiaoBai.getClass()==xiaoHei.getClass()?' + (xiaoBai.getClass() == xiaoHei.getClass()));

}

}

eat()

sleep()

com.yq.Pig===@===74a14482

com.yq.Pig===@===1540e19d

xiaoBai==xiaoHei?falseclass com.yq.Pigclass com.yq.PigxiaoBai.getClass()==xiaoHei.getClass()?true

关于 '=='

对于引用变量而言,比较的时候两个引用变量引用的是不是同一个对象,即比较的是两个引用中存储的对象地址是不是一样的。

对于基本数据类型而言,比较的就是两个数据是不是相等。

对于String类型,它是特殊而有趣的。

package com.yq;public class Test { public static void main(String[] args) { //String作为一个对象来使用

System.out.println('String作为一个对象来使用');

String str = new String('hello');

String str2 = 'he' + new String('llo');

System.out.println('str==str2?' + (str == str2));

System.out.println(str + '@' + str.hashCode());

System.out.println(str2 + '@' + str2.hashCode()); //String作为一个基本类型来使用

//如果String缓冲池内不存在与其指定值相同的String对象,那么此时虚拟机将为此创建新的String对象,并存放在String缓冲池内。

//如果String缓冲池内存在与其指定值相同的String对象,那么此时虚拟机将不为此创建新的String对象,而直接返回已存在的String对象的引用。

System.out.println('String作为一个基本类型来使用');

String s1 = 'java';

String s2 = 'java';

System.out.println('s1==s2?' + (s1 == s2));

System.out.println(s1 + '@' + s1.hashCode());

System.out.println(s2 + '@' + s2.hashCode());

System.out.println('String混合使用');

String st1 = 'hello java';

String st2 = new String('hello java');

System.out.println('st1==s2?' + (st1 == st2));

System.out.println(st1 + '@' + st1.hashCode());

System.out.println(st2 + '@' + st2.hashCode());

}

}

String作为一个对象来使用

str==str2?falsehello@99162322hello@99162322String作为一个基本类型来使用

s1==s2?truejava@3254818java@3254818String混合使用

st1==s2?falsehello java@-1605094224hello java@-1605094224

输出结果中,明明hashCode相等,为何对象不相同?

public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) {

h = 31 * h + val[i];

}

hash = h;

} return h;

}

上述String源码中,可以看出,String类是使用它的 value值作为参数然后进行运算得出hashcode的,

换句话说, 只要值相同的String不管是不是一个对象,hash值全部相等。

在Object超类中,hashCode()是一个native本地方法,看不到实现。

对象存放在内存的堆中,而基本类型则存放在内存的栈中。

二、操作符

移位操作符<<,>>,>>>

移位操作符操作的对象是二进制的'位',只能用来处理整数类型,如果对char、byte、或者short类型的数值进行移位处理,那么他们在移位之前会自动转换为int类型,结果也是int,对long处理,结果也是long。

<< : 左移运算符,低位补0,num << 1,相当于num乘以2

>> : 右移运算符,若符号为正,高位补0,若符号为负,高位补1,num >> 1,相当于num除以2

>>> : 无符号右移,忽略符号位,空位都以0补齐。

三元操作符 exp?value1:value2

若exp表达式为true,返回value1的值,否则返回value2的值,三元表达式可以嵌套。

'+'操作符,即字符串操作符,用来连接字符串。

'()type'类型转换操作符,用来强制类型转换,一般自动向上转型,不需要强转,向下转型才需要强转。

','逗号操作符,java里面唯一用到逗号操作符的地方就是for循环的控制表达式,在表达式的初始化和步进控制部分,可以使用逗号分隔的语句,但是初始化时,使用逗号表达式,必须具有想同的类型。

三、流程控制

if-else、while、do-while、for、foreach、switch。

if语句不加{},默认范围为下一条语句。

else if不是关键字,只是else后面加了一个if语句。

do-while相比while只是会先执行一次,再判断条件。

for(;;)效果和while(true)一样。

foreach语法用于数组和容器。

package com.yq;

import java.util.ArrayList;

import java.util.List;public class Test { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5}; for (int i : arr)

System.out.print(i + ' ');

System.out.println();

List ls = new ArrayList();

ls.add('a');

ls.add('b');

ls.add('c');

ls.add('d');

ls.add('e'); for (String str : ls)

System.out.print(str + ' ');

}

}//out1 2 3 4 5 a b c d e

关键字return、break、continue。

return结束整个方法,开始下一个方法。

break结束当前层的循环,开始当前层的外层的下一次循环。

continue结束当前层的当次循环,开始当前层的下一次循环。

switch的选择因子,是一个能够产生整数值的表达式,char本身就是整数。

四、类初始化

this关键字

1、表示当前类对象的引用

2、表示对调用当前方法的那个对象的引用

3、构造器调用类中的其他构造器,但是不能调用两次,并且必须放在构造器的第一行。

static关键字

static静态方法,可以通过类本身直接调用,当然类对象也可以调用static方法,但是static方法里面不能调用非静态方法,也不能出现this。

对于static修饰的类属性来说,内存只为该属性第一次初始化时分配一个地址,不管该类new了多少个对象,该属性都是同一个引用。

虽然地址是唯一的,即引用是唯一的,但是引用的值还是可以改变的。

final关键字

final作用于方式,则该方法不能被继承时覆盖,作用于参数,如果是引用类型,则该引用不能改变,但是引用的对象可以改变,如果是基本类型,则只能被赋值一次,并且不能改变。

对于一个类说来,该类的成员属性,可以不初始化,因为系统会为各成员属性设置默认值,String、对象等默认为null,数值类型为0,对应folat或者double,也有相应的小数点,char也为0,显示为空白,boolean为false,String、对象则为null。

只有类成员属性会被默认初始化,方法中必须对定义的属性或变量初始化。

初始化顺序

构造器不指定时,系统将会设置一个默认无参构造器,若指定了一个构造器,无论是否有参数,系统都不会自动设置默认构造器。

下面的例子,详细分析了,各种情况的初始化顺序:

package com.yq;class Animal { static int level; int type; static {

System.out.println('Animal static');

level = 1;

System.out.println('Animal level:' + level);

}

{

System.out.println('Animal');

type = 10;

}

Animal(int i) {

System.out.println('Animal constructor');

}

}class Pig extends Animal { static int level; int height;

Eye eye = new Eye(2); static {

System.out.println('Pig static');

level = 2;

System.out.println('Pig level:' + level);

}

{

System.out.println('Pig');

height = 20;

super.level = 3;

}

Pig(int i) {

super(i);

System.out.println('Pig constructor');

}

}class Eye {

Eye(int i) {

System.out.println(i + '只眼睛');

}

}public class Test { public static void main(String[] args) { //测试1

Pig pg1 = new Pig(2);

System.out.println(Animal.level); //测试2

Pig pg2 = new Pig(2);

Pig pg3 = new Pig(2);

System.out.println(Animal.level); //测试3

System.out.println(Pig.level);

}

}

//测试1输出Animal staticAnimal level:1Pig staticPig level:2Animal

Animal constructor2只眼睛PigPig constructor3

//测试2输出Animal staticAnimal level:1Pig staticPig level:2Animal

Animal constructor2只眼睛PigPig constructorAnimalAnimal constructor2只眼睛PigPig constructor3

//测试3输出Animal staticAnimal level:1Pig staticPig level:22

由测试1可知,初始化顺序为:父类静态成员、父类静态代码块、子类静态成员,子类静态代码块、父类成员,父类代码块,父类构造器、子类成员、子类代码块、子类构造器。

由测试2可知,静态域只初始化一次。

由测试3可知,只调用静态域时,只初始化静态域,和对象无关,静态域只由类决定。

若父类没有无参构造器,则必须用super显式调用父类构造器,不然会报错。

可变参数列表

package com.yq;public class Pig { static void test(String... args) { for (String str : args)

System.out.print(str + ' ');

System.out.println();

} public static void main(String[] args) {

test('小明', '小红', '小军', '小华');

}

}//输出小明 小红 小军 小华

其实可变参数列表,是编译器自动填充了数组。

五、访问控制权限

public、protected、包访问权限(没有关键字,默认权限)、private

对于类来说,如果一个java文件,存在public类,则java文件名必须和类型一致,而且这个文件只能存在一个public类,若整个文件都不存在public类,则java文件名和类名没有关系。

对于成员属性和方法来说,

public是最大权限,任何类都可以访问。

protected,继承访问权限,在该类的继承类中可以访问,同一个包下可以访问。

包访问权限,当没有指明权限时,默认是包访问权限,只有在同一个包下的类才能访问。

private是最小的权限修饰符,只能在本类中访问。

六、复用类。

组合:在新的类中放置任意对象,一般是private修饰该对象

继承:在新的类中隐式的放置父级对象。

组合技术通常用于想在新类中使用现有类的功能,而非他的接口。

继承技术通常用于保持现有类的形式,并可以添加新代码。

一般来说判断是否使用继承,问一问自己是否需要从新类像父类进行向上转型,如果需要则继承是必须的,否则考虑组合技术应该更合适。

七、多态

因为多态的存在,程序有了可扩展性。

package com.yq;class Animal {

public void eat(String args) { System.out.println('Animal eat():' + args);

}

}class Pig extends Animal {

public void eat(String args) { System.out.println('Pig eat():' + args);

}

}class Cat extends Animal {

public void eat(String args) { System.out.println('Cat eat():' + args);

}

}

public class Test {

public static void action(Animal anl) {

anl.eat('苹果');

}

public static void main(String[] args) { Pig pg = new Pig(); Cat ct = new Cat();

action(pg);

action(ct);

}

}//输出Pig eat():苹果Cat eat():苹果

如果程序中,需要新加动物种类,则只需定义这个类,继承Animal类即可,主程序不用做任何修改。

那么为什么编译器能这么智能的找到对应的子类对象,并且正确的调用方法呢?

原因就是:方法后期绑定,也叫作动态绑定。

意思是,在运行时根据对象的类型进行绑定,而不是在定义方法就进行前期绑定。

java中除了static和final方法(private方法也属于final方法,因为final是隐式申明的)之外,其他所有的方法都是后期绑定。

学习Java的同学注意了!!!

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:454297367【长按复制】 我们一起学Java!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多