1.java C++ 区别 :
1.运行过程:
java:java编译器 -- 字节码 -- JVM解释执行。
c++ :编译和链接后生成可执行的二进制代码。
2.纯面向对象(所有代码必须再类中实现): java不存在全局变量或全局函数
3.没有指针(有效防止了C/C++操作指针可能引起的系统问题)
4.不支持多继承(可以实现多个接口来实现多继承的目的)
5.GC帮忙释放内存
2.java程序初始化的顺序:
三个原则:
1:静态对象(变量)优先于非静态对象(变量)[静态的只初始化一次]
2:父类优先于子类;
3:按照成员变量的定义顺序;
执行顺序:1:父类静态变量 2:父类静态代码块 3:子类静态变量 4:子类静态代码块 5:父类非静态变量 6:父类非静态代码块 7:父类构造函数 8:子类非静态变量 9:子类非静态代码块 10:子类构造函数;
eg:
public classBase {static{
System.out.println("Base static block");
}
{
System.out.println("Base block");
}publicBase() {
System.out.println("Base construcor");
}
}
public class Derived extendsBase {static{
System.out.println("Derived static block");
}
{
System.out.println("Derived block");
}publicDerived() {
System.out.println("Derived constructor");
}public static voidmain(String[] args) {newDerived();
}
}
输出结果:
Base static block
Derived static block
Base block
Base construcor
Derived block
Derived constructor
3.成员变量的作用域
变量的类型主要有三种(成员变量,局部变量,静态变量)
其中成员变量的作用域对比:
作用域与可见性
当前类
同一package
子类
其他package
public
√
√
√
√
private
√
×
×
×
protected
√
√
√
×
default
√
√
×
×
4.java中有些接口没有任何方法?
标识接口
java类库中已经存在的标识接口有 Cloneable 和 Serializable等 在使用时会经常用instanceof 来判断实例对象的类型是否实现了一个给定的接口;
5.Java中的clone 方法有什么作用
java取消了指针的概念 而实质上每个new语句返回的都是一个指针的引用 (不能忽略对象和引用的区别)
public classObj {private String str = "default value";publicString getStr() {returnstr;
}public voidsetStr(String str) {this.str =str;
}publicString toString() {returnstr;
}
}
public classTestRef {private Obj aObj = newObj();private int aInt = 0;private staticObj getaObj;publicObj getaObj() {returnaObj;
}public intgetaInt() {returnaInt;
}public voidchangeObj(Obj inobj) {
inobj.setStr("changed value");
}public void changeInt(intinInt) {
inInt= 1;
}public static voidmain(String[] args) {
TestRef oTestRef= newTestRef();
Obj obj1=oTestRef.getaObj();int int1 =oTestRef.getaInt();
System.out.println("**********引用类型************");
System.out.println("调用changeObj前:" +obj1);
oTestRef.changeObj(obj1);
System.out.println("调用changeObj后:" +obj1);
System.out.println("**********基本数据类型************");
System.out.println("调用changeInt前:" +int1);
oTestRef.changeInt(int1);
System.out.println("调用changeInt后:" +int1);
}
}
输出结果:
**********引用类型************
调用changeObj前:default value
调用changeObj后:changed value
**********基本数据类型************
调用changeInt前:0
调用changeInt后:0
java在处理基本数据类型时,都是采用按值传递(传递的是输入参数的复制) ,其他类型都是按引用传递(传递的是对象的一个引用),对象除了在函数调用时是引用传递,在使用“=”赋值时也采用引用传递,示例代码如下。
public classObj {private int a = 0;public intgetA() {returna;
}public void setA(inta) {this.a =a;
}public voidchangeInt() {this.a = 1;
}
}
public classTestRef {public static voidmain(String[] args) {
Obj a= newObj();
Obj b=a;
b.changeInt();
System.out.println(a.getA());
System.out.println(b.getA());
}
}
运行结果:
1
1
已有已知对象A 创建一个具有相同状态的对象B 修改B不会影响A的状态 就需要clone;
实现:1:继承Cloneable接口;
2:重写Object类中的clone()方法;
3:在clone()方法中调用super.clone();
4: 把浅复制的引用指向原型对象新的克隆体。
public class Obj implementsCloneable {private int a = 0;public intgetA() {returna;
}public void setA(inta) {this.a =a;
}public voidchangeInt() {this.a = 1;
}
@OverrideprotectedObject clone() {
Object object= null;try{
object= super.clone();
}catch(CloneNotSupportedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}returnobject;
}
}
public classTestRef {public static voidmain(String[] args) {
Obj a= newObj();
Obj b=(Obj) a.clone();
b.changeInt();
System.out.println(a.getA());
System.out.println(b.getA());
}
}
运行结果:
0
1
当类中只有一些基本数据时 可以采用上述浅复制的方法 当类中包含了一些对象时,就需要深复制了,实现方法是在对象调用clone()方法完成复制后,接着对对象中的非基本数据类型的属性也调用clone()方法完成深度复制;
importjava.util.Date;public class Obj implementsCloneable {private Date birth = newDate();publicDate getBirth() {returnbirth;
}public voidsetBirth(Date birth) {this.birth =birth;
}public voidchangeDate() {this.birth.setTime(100);
}
@OverrideprotectedObject clone() {
Obj obj= null;try{
obj= (Obj) super.clone();
}catch(CloneNotSupportedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}//实现深复制
obj.birth =(Date) obj.birth.clone();returnobj;
}
}
6 反射机制
反射机制提供的主要功能有:
1:得到一个对象所属的类;
2:获取一个类的所有成员变量和方法;
3:在运行时创建对象;
4:在运行时调用对象的方法;
获取Class类的3种方法:
1:Class.forName("类的路径");
2:类名.Class.
3:实例.getClass().
java创建对象的4种方式:
1.new
2.通过反射机制
3.clone
4.反序列化
面向对象
1 面向对象与面向过程有什么区别
1出发点不同
2层次逻辑关系不同
3数据处理方式与控制程序方式不同
4分析设计与编码转换方式不同
2 面向对象的特征
1封装
每个类对自身数据和方法的保护 只让可信的类和对象操作 对不可信的进行信息隐藏
2继承
连结类的层次模型 并且允许,鼓励类的重用 派生类可以从它的基类继承方法和实例变量 并且派生类可以修改或增加新的方法
3多态
指允许不同类的对象对同一消息作出响应,多态性语言具有灵活,抽象,行为共享,代码共享等优势,有效的解决了应用程序函数同名问题。
1编译时多态(overload) 同一个类中有多个同名方法 但这些方法有着不同的参数。
2运行时多态(override) 子类覆盖父类方法 运行时运行子类方法。
3 抽象类(abstract class)与接口(interface)的异同
1 都不能被实例化。
2 接口的实现类和抽象类的子类都必须实现接口或抽象类的的抽象方法才能被实例化。
3 接口可以实现多继承
4 接口强调的特定功能的实现,其设计理念是“has a”关系,抽象类强调所属关系,其设计理念是“is a”关系。
5 java8以前 接口中不能有 被实现的方法 抽象类可以有。
6 接口中成员变量默认为 public static final 成员方法public abstract 抽象类可以有自己的数据成员变量 也可以有非抽象的成员方法。这些成员变量可以在子类中被重新定义 也可以被重新赋值 所以当功能需要积累时 用抽象类。
7接口被运用于实现比较常用的功能,便于日后的维护或者添加删除方法,而抽象类更倾向于充当公共类的角色,不适用于日后对里面的代码进行重新修改。
当希望支持差别较大的两个或者多个对象之间的特定交互行为时,应该使用接口
当子类与父类存在逻辑上的结构时,推荐使用抽象类;
4 内部类
5 获取父类类名
本类类名 getClass().getName()
父类类名 getClass().getSuperclass().getName()
6 this 与 super的区别
关键字
1 变量名 命名规则
标识符:变量名,函数名,数组名称。
标识符只能由数字,字母,下划线(_),$组成;第一个字符不能是数字 (必须是字母,下划线(_),$。)
2.break,continue,return 区别
1 break 用于直接跳出当前循环,不再执行剩余代码。
2 continue 用于停止当前循环,回到循环起始处,进入下一次循环。
3 return 跳转语句,表示从一个方法返回。
3 final,finally,finalize 区别
1 final 声明属性,方法,类:属性不可变 方法不可覆盖 类不可被继承(string,stringBuffer 都被final修饰 不能被继承)
2 finally 只能用在try/catch 语句中并附带一个语句块,表示这段代码最终一定会被执行,经常用在被需要释放资源的情况下。
3 finalize 再垃圾回收期执行时会调用被回收对象的finalize()方法
4 assert(断言) 约等于 if
5 static
作用:1为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。
2不创建对象的情况 通过类来直接调用方法或使用类的属性
1 static 成员变量
所有实例指向同一个内存地址
2 static 方法
不能使用this super 不能调用非static 方法 只能访问所属类的静态成员变量,静态成员方法
3 static 代码块
被用来初始化静态变量
4static 内部类
不依赖于外部类实例化对象而被实例化
只能访问外部类中的静态成员和静态方法
6 volatile
是一个类型修饰符 ,它是被设计用来修饰不同线程访问和修改的变量 ,被volatile类型定义的变量,系统每次用到它时都是直接从对应的内存中提取,而不会利用缓存,在使用了volatile 修饰成员变量后,所有线程在任何时候所看到的变量值都是相同的。
public class MyThread implementsRunnable {
private volatile booleanflag;
public voidstop() {
flag = false;
}
public voidrun() {
while(flag) {
// do something
}
}
}
停止线程最常用的方法 不取缓存中的值不导致停止不掉;
1 降低效率:不用缓存
2 修饰变量:只取内存
3 不能保证原子性 不能代替sychronized
4 慎用
字符串与数组
1字符串创建与存储的机制
String s1 = new String("abc") String s2 = new String("abc") 两个引用对象 两个相同的字符串对象 他们内存地址是不同的 new总会生成新的对象
String s1 = "abc"; String s2 = "abc"; s1 s2 引用的是同一个常量池中的对象 首先在字符串常量池中查找是否已经有相同的字符串被定义 依靠的是String类equals方法的返回值
String s ="abc" ; //把"abc"放到常量区中,在编译时产生
String s ="ab"+"c" ; //把"ab"+"c"转换为字符串常量"abc"放到常量区中
String s =new String("abc"); //在运行时把"abc"放到堆里
String s1 = "abc" ; //在常量区存放一个"abc"字符串对象
String s2 = "abc" ; //s2 引用常量区中的对象 因此不会创建新的对象
String s1 =new String("abc"); //在堆中创造一个新的对象
String s2=new String("abc"); //在堆中又创造一个新的对象
2 "==",equals和hashcode 区别
1 “==” 用来比较
基本数据类型 == 比较的是值
引用数据类型 == 比较的内存地址
2 equals
比较的是堆中的内容
3 hashcode
对象编码
3 String ,StringBuffer,StringBuilder,StringTokenizer 区别
1 String 不可变类 适合在需要被共享的场合中使用
String 字符串修改实现的原理:
创建一个StringBuilder 其次调用StringBuilder的append()方法 最后调用StringBuilder的toString()方法把结果返回
String s = "hello";
s += "world";
// 以上代码等价于下述代码:
StringBuilder sb = newStringBuilder(s);
sb.append("world");
2 StringBuffer,StringBuilder 可变类 只能用构造函数创建
适用于 字符串经常被修改的情况 都用字符串缓冲区 区别是 StringBuilder不是线程安全的 在执行效率方便 StringBuilder效率最高 其次StringBuffer,String最低
一般而言 如果要操作的数据量比较小 ,优先String 如果在单线程下操作大量数据 StringBuilder,多线程下操作大量数据 StringBuffer。
3StringTokenizer 是用来分割字符串的工具
4.数组的初始化,length属性与length()方法。
//留白
异常
输入输出流
java io流
字节流和字符流:
字节流 以字节(8bit)为单位 包含两个抽象类:inputStream(输入流) outputStream(输出流);
字符流 以字符(16bit)为单位 包含两个抽象类:Reader(输入流) Writer(输出流) ;
主要区别:字节流在处理输入输出时不会用到缓存;流的作用主要是改善程序性能并且使用方便;
javaSocket
Socket可以分为两种类型:面向连接的Socket通信协议(TCP,Transmission Control Protocol)
面向无连接的Socket通信协议(UDP,User Datagram Protocol)
基于TCP通讯过程如下:首先,Server(服务器)端Listen(监听)指定的某个端口(建议用1024+的)是否有连接请求;
其次,Client(客户端)向Server(服务器)发出Connect(连接)请求;
最后,Server端 向Client端 发回Accept(接受)消息。 连接建立 会话产生。
Nio 非阻塞io
容器
java Collections 框架
主要提供了:List ,Queue, Set ,Stack, Map
1 Set 表示数学意义上的集合概念 主要特点是集合中的元素不能重复,有唯一性,有两个实现类 HashSet 和TreeSet。 其中TreeSet 实现了 SortedSet接口,因此TreeSet容器中的元素是有序的;
2 List 有序的Collection。它按对象进入的顺序保存,所以它能对列表中的每一个元素的插入位置进行精准的控制,可以保存重复对象LinkedList ,ArrayList,Vector都实现了List接口
ArrayList 和Vector 都是动态数组实现的索引速度快 其中 Vector 线程安全 可选扩容 ,linkedList 采用双向列表来实现 对数据索引需要从头开始遍历 插入效率较高
当对数据的主要操作为索引或者只在集合末端增加,删除元素时,ArrayList或者Vector效率较高,对数据的操作主要为指定位置插入或删除 Linkedlist效率较高 多个线程会同时访问容器用Vector
3 Map Key Value结构 可以重复 但Key是唯一的 实现类有:HashMap,TreeMap,LinkedMap ,WeakHashMap,IdentityHashMap
hashMap 是 Hashtable的轻量级实现(非线程安全)HashMap 允许一个null Key
可以通过 Map =Collections.synchronizedMap(new HashMap())来达到同步效果 该方法返回一个同步的Map 封装了底层的HashMap的所有的方法。
多线程
创建线程的三种方法
继承Thread类 重写run()方法
start()方法是一个native(本地)方法 它将启动一个新线程
实现runnable接口 重写run()方法
不管是继承Thread类还是实现runnable接口 最终还是通过Thread类的对象API来控制线程的。
实现callable接口 重写call()方法 可以抛出异常
运行callable可以得到一个future对象 future对象 表示异步计算的结果,它提供了检测计算是否完成的方法,由于线程属于异步计算模型,因此无法从别的线程得到返回值,因此可以使用future来监视目标线程调用call方法的情况,当使用get方法获取结果时,当前线程就会进入阻塞,直到call方法结果返回。
thread
//创建线程类
public class MyTherad extendsThread {
@Overridepublic voidrun() {
System.out.println("继承Therad类的线程");//线程函数体
}
}
runnable
public class MyTherad1 implementsRunnable {public voidrun() {
System.out.println("实现Runnable接口的线程");
}
}
callable
importjava.util.concurrent.Callable;public class MyTherad2 implements Callable{public String call() throwsException {
System.out.println("实现callable接口的綫程");return "callable线程执行完毕";
}
}
启动三种线程
public classTest {public static voidmain(String[] args) {//继承Therad类的线程
MyTherad therad = newMyTherad();
therad.start();//实现Runnable的线程
MyTherad1 therad1 = newMyTherad1();
Thread thread2= newThread(therad1);
thread2.start();//实现callable的线程
ExecutorService theradPool=Executors.newSingleThreadExecutor();
Future future = theradPool.submit(newMyTherad2());try{
String string= future.get();//等待线程结束并获取返回结果
System.out.println(string);
}catch(InterruptedException e) {
e.printStackTrace();
}catch(ExecutionException e) {
e.printStackTrace();
}
}
多线程同步实现方法
1 Synchronized方法 Synchronized块
public Synchronized void mutiThreadAccess();
Synchronized (syncObject){
//访问syncObject代码块
}
2 wait()方法 与notify()方法
等于 手动Synchronized
3lock()重入锁 也是实现多线程的同步
1lock() 阻塞获取锁,获取到锁返回ture(); 没获取到就等待。
2trylock() 非阻塞获取锁 尝试获取锁 获取到返回ture 没获取到立即返回false
3trylock(long timeout,timeunit unit)设置等待时间
4lockinterruptibly()当前线程被别的线程中断会抛出异常lock()不会;
終止线程的方法
Stop()
释放所有的监视资源
suspend()
挂起容易造成死锁 比如线程A获取到互斥资源M的锁 挂起,接着B去访问互斥资源M 就造成了死锁
所以 一般用Volatile 做一个flag;
public class MyThread implementsRunnable {private volatile booleanflag;public voidstop() {
flag= false;
}public voidrun() {while(flag) {//do something
}
}
}
但是 当线程处于非运行状态(sleep wait I/O阻塞),不行,此时需要interrupt()方法打破阻塞状态,会抛出InterruptedException异常,可以通过run()方法捕获这个异常让线程安全退出。