Java基础(一)

数据类型和标识符

java不常见的关键字

goto 保留关键字
transient 短暂的
trictfp
volatile 不稳定的
const 保留关键字
native 原始的

浮点型

因为java浮点数使用的是二进制数据的科学计数法表示,所以在实际生活中不会特别的精确。
如果开发者需要精确保存一个浮点数,则可以考虑使用BigDecimal类;
Java提供了三个特殊的浮点数值:正无穷大,负无穷大和非数。
正数除以零得到正无穷大;
负数除以零得到负无穷大
0.0除以0.0或者一个负数开发将得到一个非数;
正无穷大(Double.POSITIVE_INFINITY;Float.POSITIVE_INFINITY)都是相等的,负无穷大(NEGATIVE_INFINITY)都是相等的,然而非数(NaN)不与任何数相等,NaN和NaN也是不相等的。
注意,只有浮点数除以0才会得到无穷大,因为java会把浮点数运算的0当成0.0运算。正数除以0会抛出除0异常

数值中间可以使用下划线

由于数值较大时,较难越阅读,java7中加入相应的特性,可以在正数和浮点数中添加下划线;
如 int i = 1_000;

运算

java中较为复杂的运算定义在java.lang.Math类中
常用的有
Math.pow(a,b):a的b次幂
Math.sqrt(a):a的平方根;
Math.random():0-1的随机数

条件分支

使用if…else语句时,一点要先处理包含范围更小的情况.
switch分支语句,switch语句后边的数据类型可以是:byte,short,char,int,java7后可以使用java.lang.String或者枚举类型.

控制循环结构

break:用来结束当前循环
当break要结束嵌套循环的外层循环时,可以加上标签名;如break ourter;,java中的标签就是一个紧跟着冒号(:)的标识符.java中的标签只有放在循环语句之前才有作用.
continue:忽略本次循环剩下的语句,开始下次的循环;
continue也可以跟上标签;
return:结束方法

数组的定义

数据的初始化:
1,静态初始化:初始化有程序员指定每个数组的初始值,由系统决定长度;
2,动态初始化:程序员决定长度,系统为数组袁术分配初始值.
静态:
1,type[] arrayName = new type[] {element1,element2...};
2,type[] arrayName = {element1,element2...};
动态:
type[] arrayName = new type[length]

foreach循环

java5之后定义了foreach循环,可以用来遍历数组和集合;
不要在foreach中对循环变量进项赋值,这个变量仅仅是临时的(用于把数组的元素赋值给它),不是数组的元素

二维数组的定义和初始化

1,type[][] arrayName = new type[length][]
2,type[][] arrayName = new type[length1][length2]
从某个角度看,java中没有多维数组

工具类Arrays

  1. int binarySearch(type[] a,type key),使用二分法查询key在数组中的索引.要求数组必须是按升序排列过的.
  2. int binarySearch(type[] a,int fromIndex,int toIndex,type key);二分法查询key的索引,但只搜索fromIndex到toIndex索引之间的元素,要求数组必须是按升序排列过的.
  3. type[] copyOf(type[] original,int length)这个方法将会把orginal数组赋值成一个新数组,其中length是新数组的长度,如果length小于original数组的长度,则新数组包含前length个元素;如果length大于original数组的长度,则数组包含origianl数组的说有元素,length索引以及以后的元素是类型的初始值.
  4. type[] copyOf(type[] original,int from,int to)这个方法只复制from索引到to索引的元素;
  5. boolean equals(type[] a,type[] b)比较两个数组,如果数组a和b的长度相等,且里边的元素也相等,则返回true;
  6. void fill(type[] a,type val)将a数组的所有元素赋值为val;
  7. void fill(type[] a,int fromIndex,int toIndex,type val)将索引区间的元素赋值为val
  8. void sort(type[] a)对a数组进行排序
  9. void sort(type[] a,int fromIndex,int toIndex),把区间的元素进行排序
  10. String toString(type[] a)将数组转化为字符串
    复制数组的方法,除了以上的方法,Syetem类也定义了一个static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length),该方法将src数组里的元素赋值给dest数组的元素,其中srcPos指定从src数组的第几个元素开始赋值,destPos指的是dest数组的第几个元素开始,length参数指定将src数组的多少个元素值赋值给dest数组的元素.
    java8增强了Array类的功能:为Arrays类增加了一些工具方法,这些工具方法可以充分利用CPU并行的能力;
  • void parallelPrefix(xxx[] array,XxxBinaryOperator op)使用op参数计算的结果作为新元素.op的参数由两个,left代表前一个元素,right代表当前元素,当计算第一个新数组时,left的值默认是1;
  • void parallelPrefix(xxx[] array,int fromIndex,int toIndex,XxxBinaryOperator op)该方法与上一个相似,区别是该方法仅重新计算fromIndex到toIndex索引的元素
  • void (parallel)setAll(xxx[] array,IntToXxxFunction generator);使用生成器为所有元素赋值
  • void parallelSort(xxx[] a)并行排序
  • spliterator.ofXxx spliterator(xxx[] array)将数组的所有元素转换成对应的Spliterator对象
  • XxxStream stream(xxx[] array);生成流

方法参数的传递

调用方法时,方法值的传递是值得传递;
当传递的是基本数据类型时,仅仅把值拷贝一份传过去,对原来的变量没有影响;
但传递的是引用数据类型时,把引用拷贝一份传递过去,因为引用指向对象,所有会对原对象产生影响.

形参个数可变的方法

从JDK1.5之后,java允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参.如果在定义方法时,在最后一个形参的类型后增加三个点(…),则表明可以接受多个参数值.多个参数值被当成数组传入(实际上调用时,也可以传数组),但这中参数只能位于形参的最后一个,即一个方法只能由一个可变的参数

方法的重载

方法的重载:如果方法的形参中含有可变的参数,如test(String msg);和test(String… msgs);当完全匹配一般参数时,不会调用拥有可变参数的方法,只会调用一般方法.当要调用可变参数方法并且只由一个参数,可以传递数组;

面向对象

类和对象

当第一次使用类时,系统通常会去加载这个类,并初始化。
当使用类变量时,要使用类去调用,提高代码的可读性;

import

import package.subpackage…*;
只能代表类不能代表类,不能代表包;例如:import lee.* 只能导入lee包下的类,不能导入lee包子包的类;
JKD1.5后,增加了一种静态导入的语法,用于导入指定类的摸个静态成员变量、方法或全部的静态成员变量、方法
import static package.supackage...ClassName.fieldName|methodName;

构造器

若构造器B完全包含构造器A,则需要在B中调用A,如果使用new 关键字,就会多创建一个对象,这时使用this(类似于类内对用方法):

public Demo {
	public Demo(int age,String name){
		this.age = age;
		this.name = name;
	}
	
	public Demo(int age,String name,char sex){
		this(age,name);
		this.sex = sex;
	}
}

this调用构造方法只能在构造方法中使用,且必须在第一行;

继承

值得指出的是,java的子类不能获得父类的构造器;

super限定

用于限定该对象调用它从父类继承得到的实例变量或方法,不能出现在static修饰的方法或代码块中.一般情况下子类定义一个和父类相同的成员变量时,会隐藏掉父类的实例变量(并不是覆盖).可以在子类的实例方法中通过super来访问父类中被隐藏的实例变量.
创建实例时,直接或者间接父类名称相同的成员变量也都会被继承下来,并分配内存空间,但只是被隐藏而已,通过强转,(如果子类修饰符时private时)也能够获取继承到的属性.
方法中访问变量a时,默认采用以下顺序取得变量中的值:

  1. 该方法中是否存在a的局部变量;
  2. 当前类是否有名为a的成员变量;
  3. 当前类的直接父类是否有a的成员变量,如果没有继续向上找,直到出现编译错误;
    上边的说明中由于修饰符时private,就会从大父类中取值.

构造器

子类通过super在构造器中调用父类的构造器;也必须放在构造器代码的第一行,因为this调用构造器也要放在第一行,所以构造器中不可能同时含有this和super;
无论是否调用super,子类总会调用一次父类的构造器一次:

  1. 在首行显式地调用父类地构造器;
  2. 使用this调用其他的构造器,其他的构造器调用父类的构造器;
  3. 既没有this也没有super,默认调用父类的无参构造;
    所以创建对象时总会先调用父类的构造器,也就是总要先调用Object的构造器;

多态

当编译变量和运行实例变量不是一个类型时,使用方法时会出现多态,使用实例变量不会出现多态(使用实例变量是总是调用,该编译类型自身的成员变量);
书写代码时,只能调用编译类型的方法,不能调用运行类型的特有方法。这时候需要强制类型转换(将父类转换为子类,前提是运行的类型就是子类,不然会报类转换异常);
考虑到强转是会出现异常,因此在类型强转前应先通过instanceOf运算符判断,是程序更加健壮;
instanceOf的使用:前边的变量的类型必须等同于后边的类型或者是后边类型的父类。不然会报异常;

组合

继承可以很简单地进行复用父类的属性和方法,但这是会破坏父类的封装,产生较大的耦合(能够直接访问父类的属性和方法);
为了防止破坏父类的封装,设计父类是应该注意:

  1. 尽量隐藏父类的内部数据;
  2. 不要让子类可以随意访问、修改父类的方法。作为其他方法使用的工具方法应该用private修饰,不让子类访问;若想被外部访问又不想让子类重写,应使用public final;若想被子类重写,但不想被外部引用,则使用protected修饰;
  3. 尽量不要在父类构造器内调用要被子类重写的方法。

当不希望被继承时,使用final修饰类。除此之外,使用private修饰所有构造器时,导致子类无法访问该类的构造方法,因此也无法被继承,但应该给出public static 的方法用来创建对象。

何时使用继承:除了保证子类是一种父类的情况下,还需:

  1. 子类还需要额外的属性。
  2. 子类需要增加自己独有的行为方式(包括新加的方法或重写父类的方法);

如果仅仅是复用,那么可以采用组合实现复用;
组合是把旧类的对象作为新类的成员变量组合进来。

组合和继承的选择,主要看是什么关系;is-a的关系使用继承,has-a关系使用组合关系;

初始化代码块;

java采用构造器对单个对象进行初始化操作;初始化代码块也可以对java对象进行初始化;
代码块也是累的一种成员;
可以定义多个代码块,先定义的先执行。
java在初始化时,先执行执行代码块,再执行构造器。因此没有必要使用两个代码块;

普通初始化块、声明实例变量指定的默认值都可认为是对象的初始化代码。

public class A{
	{a = 6int a = 9;
	//最后的结果是a = 9;

如果对所有对象多有相同的初始化代码,那么可以提取出来写在初始化代码块中;
实际上在java编译时,把初始化代码块放到每个构造器内,且放在前边;
初始化对象时,会先使用父类的初始化代码,构造器再执行子类的初始化代码和构造器;

静态代码块

静态代码块也叫类代码块,在类初始化时执行,不负责实例的初始化。因此在初始化代码块之前执行;
类初始化时,先执行Object的静态代码块,再执行父类的静态代码块,最后执行该类的静态代码块。
静态初始化块和声明静态成员变量时所指定的初始值都是该类的初始化代码,他们的执行顺序与源程序中的排序顺序相同。

面向对象(高级)

JDK1.5后提供了基本数据类型到包装类的自动装箱和自动拆箱。
基本数据类型到包装类型:
char -> Character

  1. 包装类型的parseXxx(String s)可以把字符串类型转换为相应的基本数据类型。(Integer.parseInt())
  2. 利用构造器可以把String转为包装类;new Integer(String s);new Integer(int i);基本数据类型转为包装类;
  3. String类型也提供了多个重载的valueOf()方法,将基本数据类型装换成字符串;当然可以使用 + “”;

使用须知:使用Integer的包装类,在-128到127之间都会放到一个缓存数组里边,使用==指向同一个元素,会返回true,其他的都会返回false(因为是引用数据类型);

在JDK1.7位包装类型添加了比较的方法;
包装类型.compare(xxx val1,xxx val2);例如int compare = Integer.compare(2, 1);
如果前边大于后边返回1,相等返回0,小于返回-1;

Object

所有的java实例都可以调用Object的实例方法.

toString

打印或者使用+ “”,都会调用toString方法.同String方法表示自我描述,Object默认的同String方法是:类名 + @ + hashCode;
用户可以自定义toString来进行自我描述.

==和equals方法

== :

  1. 比较基本数据类型,数值相等时(不必时同一种数据类型)返回true;
  2. 比较引用数据类型,指向同一个对象时才返回true;当比较引用数据类型时必须两边类型是父子关系或者同一类型,否则编译报错.
    equals方法:
  3. 在Object类型中,和==效果一样;
  4. 用于比较对象的值,但需要自己去定义equals方法,例如String的equals方法;

重写equals方法应满足下列条件:

  • 自反性
  • 对称性
  • 传递性
  • 一致性
  • 对任何不是null的x,x.equals(null)均返回false

使用字符串.若使用直接量"hello",JVM会使用常量池来管理它.
但使用new String(“hello”);时,先使用常量池管理"hello"直接量,在使用构造器创建一个新的对象,此时产生2个对象:直接量和String对象.
常量池专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据.它包括了关于类,方法,接口中的常量,还包括字符串常量.

final成员变量

final修饰的成员变量(实例变量和类变量)必须由程序员显式地指定初始值;
类变量:必须在静态代码块或者指定静态变量时指定初始值.
实例变量:必须在分静态初始化块,声明该实例变量或者构造器中指定初始值.
final修饰的成员变量在被赋值之前访问会出现错误.

final修饰的基本数据类型和引用数据类型

final修饰的基本数据被赋值后,不能再修改
final修饰的引用数据类型,变量仅仅存放对象的引用.只能保证存放的引用不再发生变化.但引用的对象是可以变化的.

可执行“宏替换”的final变量

对于一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足三个条件,这个fianl变量就不再是一个变量,而是相当于一个直接量:

  1. 使用final修饰符修饰;
  2. 在定义该final变量时指定了初始值;
  3. 该初始值可以在编译时就被确定下来;
    java在编译的时候,把用到该变量的值直接转换成该变量的值。
	final String str = "疯狂" + "Java";//编译时能够确定下来,是宏变量;
	final String book = "疯狂Java讲义:" + 99.0;//宏变量;
	final String book2 = "疯狂Java讲义:" + String.valueOf(99.0);//因为需要调用String的方法 ,编译时不能直接确定,因此不是宏变量;
	System.out.println(book == "疯狂Java讲义:99.0");//true
	System.out.println(book2 == "疯狂Java讲义:99.0");//false

	String name = "zhangsan";
	String name1 = "zhang" + "san";
	
	String  str1 = "zhang";
	String str2 = "san";
	String name2 = str1 + str2;
	
	final String  str3 = "zhang";
	final String str4 = "san";
	String name3 = str3 + str4;
	
	System.out.println(name == name1);//ture
	System.out.println(name == name2);//false
	System.out.println(name == name3);//true
	

final 修饰的实例变量只有定义时赋值才有宏变量的效果;

不可变类

java中的String和8个包装类型都是不可变类型.所产生的实例都时不可改变的.
如果要创建自己的不可变类,可遵循如下的规则:

  1. 使用private和final修饰符来修饰该类的成员变量;
  2. 提供带参数构造器,用于根据传入参数来初始化类里的成员变量;
  3. 仅为该类的成员变量提供getter方法,不要为该类的成员变量提供setter方法,因为普通方法无法修改final修饰的成员变量.
  4. 如果有必要,从写Object类的hashCode()和equse()方法.除此之外,还应该保证两个用equals()方法判断为相等的对象的hashcode()也相等.

需要注意的时,由于final修饰的引用类型的对象可以发生变化,当对象变化时,这个不可变类的设计就是失败的.可采用一下做法:

	//在构造函数的时候指向一个匿名对象:
	public Person(Name name) {
		this.name = new Name(name.getFirstName(),name.getLastName());
	}
	
	//getter方法返回一个新的对象
	public Name getName(){
		return new Name(this.name.getFirstName(),this.name.getLastName());
	}

使用不可变类的实例时,如果使用较多时,考虑使用不可变类实例的缓存.最简单的方法时在类里边添加一个数值存放实例,控制数组内的实例只能出现一次;
例如:Integer,调用new Integer();时,创建一个Integer实例.使用Integer.valueOf时则是从缓存中获取.但Integer只缓存-128-127之间的数据;

—214

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值