Java运行机制
Java虚拟机(Java Virtual Machine):
Java虚拟机可以理解成一个以字节码为机器指令的CPU;对于不同的运行平台,有不同的虚拟机;
Java虚拟机机制屏蔽了底层运行平台的差别,真正实现了“一次编译,随处运行”。
Java垃圾回收(Garbage Collection):
不用使用的内存空间应该回收;在C/C++等语言中,由程序员负责回收无用的内存;
Java语言消除了程序员回收无用内存的职责,它提供一种系统级线程跟踪存贮空间的分配情况,
并在JVM空闲的时候,检查并释放那些可以被释放的内存空间;
垃圾收集在java程序运行过程中自动进行,程序员无法控制和干预。
Java运行过程
Java源文件(*.java)——>Java编译器——>字节码文件(*.class)——>
类装载器——>字节码校检器——>解释器——>操作系统(Windows、Linux等)
整个文件Load到内存区,一系列动作之后形成操作系统认识的代码,
操作系统找到main方法开始实行。
heap——>new 出来的东西放在这里
stack——>局部变量
data segment——>静态变量或字符串常量
code segment——>存放代码
JRE:Java Runtime Enviroment Java 运行时环境
JVM:Java Virtual Machine Java虚拟机
Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、
一个垃圾回收堆和一个存储方法域。
JVM屏蔽了与具体操作系统平台相关的信息,
使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),
就可以在多种平台上不加修改地运行。
JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
JDK:Java Development Kit,JDK 是整个Java的核心,包括了Java运行环境、Java工具和Java基础类库。
Java运行过程:
Java源文件(*.java)——>Java编译器——>字节码文件(*.class)——>
类装载器——>字节码校检器——>解释器——>操作系统(Windows、Linux等)
Java基本数据类型(4,2,1,1):
Java中所有数据均为有符号数据
整型
Java中所有整数均为整型
byte 字节 -2^7 ~ +2^7 - 1
short 短整 -2^15 ~ +2^15 - 1
int 整型 -2^31 ~ +2^31 - 1
long 长整 -2^63 ~ +2^63 - 1
浮点型
在java中,所有浮点数均为double
float 点精度有效数字7~8
dobule 双精度有效数字15~16
字符型
char 最少占2个字节
GBK GB2312
UTF-8
布尔型
boolean 表示真或假
true false
如果是Windows2000、XP或Win7系统,使用鼠标右击“我的电脑”->属性->高级->环境变量
what is Java:Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言
Java和C的区别:
Java和C都是指令式语言(Imperative Language),不同的是Java有面向对象(OO)成分在里面,
而C是完全面向过程的,C的高级版本C++、C#支持面向对象。
另外一个不同是,Java跨平台,既不同的操作系统都可以通过JVM来解释Java程序,
而C、C++、C#则是与平台相关的,有些指令只在某些操作系统中才能执行。
具体原因是,Java是解释型语言,所有代码都会翻译成统一的、与系统无关的bytecode,
然后放到JVM上运行;而C是编译式语言,代码要先通过编译器转换成与系统相关的中间代码,然后才能运行。
再一个不同是,Java不支持系统调用,既无法与操作系统进行交互,这是由它跨平台的特点决定的,
而C则可以调用系统中的指令,如fork()。
这也就是为什么Java中只有线程(Thread)概念而没有进程(Process)概念,而C两者均有。
再者,Java无法对内存进行控制,而C则可以通过指针对内存进行人为分配。
还有一点,Java有Gabbage Collection机制,可以自动回收不再使用的空间,而C则要用free()函数释放空间。
循环控制
只能跳出最近的循环
可以在swith和循环中使用
break 打断循环
只能在循环中使用
continue 跳过本次循环,继续执行下次循环
标签
break label 跳至指定标签,并且跳过标签后的代码
continue label 跳至指定标签,继续执行余下代码
面向对象 = 对象 +消息
用计算机语言描述现实世界的物体,然后用编程逻辑来组织对象处理问题
面向过程 = 算法 +数据结构
关心算法,数据结构
面向对象三个特点:
封装性:封装是一种信息隐藏技术,它体现于类的说明,是对像的重要特性
继承:自动共享父类数据和方法的机制
多态:是由对象根据消息自行决定该如何响应
Java语言的三大特性即是:封装、继承、多态
首先先简单的说一下其3大特性的定义:
封装:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。封装的基本要求是: 把所有的属性私有化,对每个属性提供getter和setter方法,如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。在开发的时候经常要对已经编写的类进行测试,所以在有的时候还有重写toString方法,但这不是必须的。
继承:通过继承实现代码复用。Java中所有的类都是通过直接或间接地继承java.lang.Object类得到的。继承而得到的类称为子类,被继承的类称为父类。子类不能继承父类中访问权限为private的成员变量和方法。子类可以重写父类的方法,及命名与父类同名的成员变量。但Java不支持多重继承,即一个类从多个超类派生的能力。在开发中尽量减少继承关系,这样做是为了把程序的耦合度降低。
多态:多态又分为设计时多态和运行时多态,例如重载又被称为设计时多态,而对于覆盖或继承的方法,JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态。总而言之,面向对象的设计的典型特点就是继承,封装和多态,这些特点也是面向对象之所以能如此盛行的关键所在。
java中重载与重写的区别:
重载(Overloading)
(1) 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。
重载Overloading是一个类中多态性的一种表现。
(2)Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。
调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。
(3) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。
重写(Overriding)
(1) 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。
但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。
方法重写又称方法覆盖。
(2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。
如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
(3)子类函数的访问修饰权限不能少于父类的;
重写方法的规则:
1、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。
2、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。
3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:
父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。
而重载的规则:
1、必须具有不同的参数列表;
2、可以有不责骂的返回类型,只要参数列表不同就可以了;
3、可以有不同的访问修饰符;
4、可以抛出不同的异常;
方法参数: 值传递
对象作为参数传递同样进行值传递
但是因为对象内部保存的是一个对象引用,所有参数传递后,形参和实参所引用的对象为同一对象
继承
共享父类之间的数据和方法
方便修改代码
extends
不能继承父类的私有属性和方法
Java中只允许单重继承
先实例化父类再实例化子类
通过super关键字调用父类构造器,必须在构造器中的第一行
重写要求
1.返回值必须相同
2.方法名一致
3.参数列表一致
4.访问权限不能小于父类
5.必须发生在继承关系中的子类
6.不能重写父类构造器
super的用法有两种:
1、super()表示调用父类的构造函数
2、super.此处super代表父类对象
抽象类
以abstract声明的类
只要一个类中包含一个抽象方法,这个类一定是抽线类
抽象类中不一定包含抽象方法
抽象类可以继承抽象类,所有抽象方法方法由第一个非抽象子类实现
抽象方法,由第一个非抽象子类实现
只要有一个抽象方法,类必须为抽象类
抽象类不一定包含抽象方法
不能抽象属性
抽象方法不能声明为private或者final方法
接口:interface:解决java多继承
接口不是类,是对一组要求的描述
100%抽象
所有方法均为抽象方法
所有方法默认为abstract方法,所以可以不用将方法标记为abstract
所有变量默认为static final变量
implements:实现接口
class A implements Interface
接口继承接口,接口可以实现多继承
interface B
interface C
interface A extends B, C
接口的特点:
1.接口是对外暴露的规则
2.接口是程序的功能扩展
3.接口可以用来多实现
4.类与接口之间是实现关系,而且
类可以继承一个类的同时实现多个接口
5.接口与接口之间可以有继承关系
异常处理
异常 != 错误
Throwable
Excpetion Error
RuntimeException Exception
运行时异常 非运行时异常
未检查异常 检查异常
RuntimeException 数组越界 空指针 ...
Exception IO
1.RuntimeException,也就是运行时异常,表示你的代码本身存在BUG,比如你提到的ArrayIndexOutOfBoundsException,数组下标越界,这个属于代码有问题,数组定义的长度不够实际使用,不处理肯定会报错,如果你操作某个模块发现能正常运行,那只是因为代码还没跑到这个错误的地方而已。。控制台一旦报RuntimeException,就必须要处理。。没有例外的。而且,处理RuntimeException,不是try-catch能解决的。。try-catch在这里使用毫无意义。
2.不是RuntimeException,就是编译时异常,异常只有这两种了。比如你在处理文件流时的I/O问题,就属于编译时异常。这个时候用thr{}catch 来捕获或者 throws即可。
3.error,就不在这里赘述了。
throws是用来声明一个方法可能抛出的所有异常信息
throw则是指抛出的一个具体的异常类型。
通常在一个方法(类)的声明处通过throws声明方法(类)可能抛出的异常信息,而在方法(类)内部通过throw声明一个具体的异常信息。
throws通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法;
throw则需要用户自己捕获相关的异常,而后在对其进行相关包装,最后在将包装后的异常信息抛
ADT:abstract data type
/* 选择排序。 内循环结束一次,最值出现头角标位置上。 */ public static void selectSort(int[] arr) { for (int x=0; x<arr.length-1 ; x++) { for(int y=x+1; y<arr.length; y++) { if(arr[x]>arr[y]) { int temp = arr[x]; arr[x] = arr[y]; arr[y]= temp;
} } } } /* 冒泡排序 */ public static void bubbleSort(int[] arr) { for(int x=0; x<arr.length-1; x++) { for(int y=0; y<arr.length-x-1; y++)//-x:让每一次比较的元素减少,-1:避免角标越界。 { if(arr[y]<arr[y+1]) { int temp = arr[y]; arr[y] = arr[y+1]; arr[y+1] = temp;
} } } }
常见的排序方法有:冒泡排序、快速排序、选择排序、插入排序、希尔排序,甚至还有基数排序、鸡尾酒排序、桶排序、鸽巢排序、归并排序等。
接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承实体类,但前提是实体类必须有明确的构造函数。
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
①==和equals的实质。
在JAVA中利用"=="比较变量时,系统使用变量在"栈"中所存的值作为比较的依据。
基本数据类型在"栈"中存的是其内容值,而对象类型在"栈"中存的是地址,这些地址指向"堆"中的对象。
java.lang包中的Object类有public boolean equals(Object obj)方法,它比较两个对象是否相等。
其它对象的equals方法仅当被比较的两个引用指向的对象内容相同时,对象的equals()方法返回true。
总之,"=="和"!="比较的是地址.也可认为"=="和"!="比较的是对象句柄;而equals()比较的是对象内容.或者说,,"=="和"!="比较的是"栈"中的内容,而equals()比较的是"堆"中的内容.
②==操作符。专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相当,只能用==操作符。
Java的基本数据类型为(char,byte,short,int,long,float,double,boolean)。
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(对内存),变量本身也占用一块内存,例如Object obj = new Object()变量obj是一个内存,new Object()是一个内存,此时,变量所对应的内存中存储的数据就是对象占用的那块内存的首地址。对于指向对象内存的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
移植自定义View过程中遇到的问题及解决方法
2012-01-12
问题背景:最近在做camera界面调整的时候,界面需要参考2.3.5的switcher控件,如下:
功能是相机和摄像机相互切换,在移植到SP8825平台上时,发现布局出现颠倒现象,变为:
跟踪到相应布局文件,发现最外层LinearLayout的orientation是vertical即垂直布局,改成水平的horizontal后布局变成:
再次查看图片,发现图片是垂直的,再次把图片旋转,这次布局正常了,但是发现里面小圆圈开关滑动到右侧的时候就消失了,怎么调也调不出来,在这里卡住了很久,今天终于完美解决,问题现象如下:
滑动小圆圈开关--> 继续滑动-->
再滑动--> 再往右滑就变成--> 小圆圈开关消失
期间加了很多Log跟踪调试,定位问题在自定义view的Switcher.java文件中,发现控件的getWidth()值和getHeight()的值均是57,这里发现就是小圆圈的长宽,getWidth()这个是View.java中的方法,布局代码如下:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/camera_switch_set"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_marginBottom="30dp"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<com.android.camera.RotateImageViewandroid:id="@+id/video_switch_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="/blog_article/@drawable/btn_ic_mode_switch_video/index.html"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="70dp"
android:layout_height="35dp"
android:background="@drawable/btn_mode_switch_bg">
<com.android.camera.Switcher–>切换控件
android:id="@+id/camera_switch"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="/blog_article/@drawable/btn_mode_switch_knob/index.html" />
</LinearLayout>
<com.android.camera.RotateImageView
android:id="@+id/camera_switch_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginBottom="3dp"
android:src="/blog_article/@drawable/btn_ic_mode_switch_camera/index.html"/>
</LinearLayout>
Switcher继承的是ImageView类,如果在Switcher.java文件中调用getWidth()方法,得到的应该是上述代码中标记为浅蓝色LinearLayout的背景的宽度,也即btn_mode_switch_bg这张图片的宽度,而实际结果并不是如此。
于是重新看了一下自定义View的一些事项:
发现自定义view中有一个onMeasure()方法,查看该方法的作用:
onMeasure方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec。
它们指明控件可获得的空间以及关于这个空间描述的元数据。
比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。
接下来的代码片段给出了如何重写onMeasure。注意,调用的本地空方法是来计算高度和宽度的。它们会译解widthHeightSpec和heightMeasureSpec值,并计算出合适的高度和宽度值。
查看后明白:要解决此问题,必须要重写这个方法:
@Override
protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getMeasuredLength(widthMeasureSpec,true),getMeasuredLength(heightMeasureSpec, false));
}
private int getMeasuredLength(int length,boolean isWidth) {
intspecMode = MeasureSpec.getMode(length);
intspecSize = MeasureSpec.getSize(length);
intsize;
intpadding = isWidth ? getPaddingLeft() + getPaddingRight()
:getPaddingTop() + getPaddingBottom();
if(specMode == MeasureSpec.EXACTLY) {
size= specSize;
}else {
size = isWidth ? padding + getDrawable().getIntrinsicWidth()* 2 : getDrawable().getIntrinsicHeight() + padding;//这里指定相应的宽度和高度
if(specMode == MeasureSpec.AT_MOST) {
size= Math.min(size, specSize);
}
}
returnsize;
}
至此,这个问题终于解决完成了~