java语言基础
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java语言基础相关的知识,希望对你有一定的参考价值。
一、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() + "[email protected]===" + 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[email protected]===74a14482 com.yq.Pig[email protected]===1540e19d xiaoBai==xiaoHei?false class com.yq.Pig class com.yq.Pig xiaoBai.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?false [email protected]99162322 [email protected]99162322 String作为一个基本类型来使用 s1==s2?true [email protected]3254818 [email protected]3254818 String混合使用 st1==s2?false hello [email protected]-1605094224 hello [email protected]-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<String> 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 + " "); } } //out 1 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 static Animal level:1 Pig static Pig level:2 Animal Animal constructor 2只眼睛 Pig Pig constructor 3
//测试2输出 Animal static Animal level:1 Pig static Pig level:2 Animal Animal constructor 2只眼睛 Pig Pig constructor Animal Animal constructor 2只眼睛 Pig Pig constructor 3
//测试3输出 Animal static Animal level:1 Pig static Pig level:2 2
由测试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语言基础的主要内容,如果未能解决你的问题,请参考以下文章