以下语句创建了两个字符串对象 "疯狂Java"对应的字符串对象和由new String()返回的字符串对象
String java = new String("疯狂Java")
Java程序中创建对象的常规方式由以下四种:
- 通过new调用构造器创建Java对象
- 通过Class对电工的newInstance() 方法调用构造器创建Java对象
- 通过Java的反序列化机制从IO流中回复Java对象
- 通过Java对象提供的clong()方法复制一个新的Java对象
两个==的值对比确定
决定于在编译时能不能确定,可以的话引用的变量会指向同一个字符串
public class StringJoinTest2 {
public static void main(String[] args) {
String str1 = "Hello Java的长度:10";
//因为str2的值包含了方法调用,因此不能再编译时确定false
String str2 = "Hello "+"Java"+"的长度:"+"Hello Java".length();
System.out.println(str1 == str2);
int len = 10;
//因为str3 的值包含了变量,因此不能再编译时确定false
String str3 = "Hello "+"Java"+"的长度:"+len;
System.out.println(str1 == str3);
//因为str的值再编译时就能确定,因此为true
String str = "Hello "+"Java"+"的长度:10";
System.out.println(str == str1);
}
}
以下代码在创建的时候,创建了一个对象,因为在创建时就直接把这个字符串常量放入字符串池里面而不存在三个间断字符串
String str = "Hello"+"Java"+".org";
String对象一旦创建String类里包含的字符序列就被固定下来了。拼接String事实上只是把堆内存里面的字符串进行拼接,而并未改变String不可变的事实。但是这样会留下一块无引用的字符串垃圾。推荐使用(StringBuilder)
switch表达式:
表达式的类型只能是以下五种数据类型:
- byte: 字节类型
- short:短整型
- int:整形
- char:字符型
- enum:枚举型
instanceof运算符: 前一个操作数通常是一个引用类型的变量,后一个操作数通常是一个类(也可以是接口,可以把接口理解未一种特殊的类),它用于判断签名的对象是否是后面的类或其子类,实现类的实例。如果是返回true,不是返回false。
关闭资源正确方法:
finally{
if(oos!=null)
{
try
{
oos.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
if(ois!=null)
{
try
{
ois.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
关闭资源的方法是主要保证以下三点:
- 使用finally块来关闭物理资源,保证关闭操作总是会被执行;
- 关闭每个资源之前首先保证引用该资源的引用变量不为null
- 为每个物理资源使用单独try…catch块关闭资源时引发的异常不会影响其他资源的关闭
如果在程序中执行System.exit(0);finally语句并不会被执行到。
数据存在以下四种基本逻辑结构:
- 集合:数据元素之间只有“同属于一个集合”关系。
- 线性结构:数据元素之间存在一个对一个的关系
- 树形结构:数据元素之间存在一个对多个的关系
- 图状结构或网状结构:数据元素之间存在多个对多个的关系
二叉树
满二叉树是一种特殊的完全二叉树,当完全二叉树最后一层的所有节点都是满的时,这棵完全而擦函数就变成了满二叉树
遍历二叉树的方式:
- 深度优先遍历
- 广度优先遍历
- 先序遍历
- 中序遍历
- 后序遍历
先序遍历
- 访问根节点
- 递归遍历左子树
- 递归遍历右子树
public List<TreeNode> preIterator()
{
return preIterator(root);
}
private List<TreeNode> preIterator(TreeNode node)
{
List<TreeNode> list = new ArrayList<TreeNode>();
list.add(node);
//递归处理左子树
if(node.left!=null)
{
list.addAll(preIterator(node.left);
}
//递归处理右子树
if(node.right!=null)
{
list.addAll(preIterator(node.right);
}
returen list;
}
中序遍历
- 访问左子树
- 访问根节点
- 递归遍历右子树
public List<TreeNode> inIterator()
{
return inIterator(root);
}
private List<TreeNode> inIterator(TreeNode node)
{
List<TreeNode> list = new ArrayList<TreeNode>();
//递归处理左子树
if(node.left!=null)
{
list.addAll(inIterator(node.left);
}
//处理根节点
list.add(node);
//递归处理右子树
if(node.right!=null)
{
list.addAll(inIterator(node.right);
}
returen list;
}
后序遍历
- 递归遍历左子树
- 递归遍历右子树
- 访问根节点
public List<TreeNode> postIterator()
{
return postIterator(root);
}
private List<TreeNode> postIterator(TreeNode node)
{
List<TreeNode> list = new ArrayList<TreeNode>();
//递归处理左子树
if(node.left!=null)
{
list.addAll(postIterator(node.left);
}
//递归处理右子树
if(node.right!=null)
{
list.addAll(postIterator(node.right);
}
//处理根节点
list.add(node);
returen list;
}
广度优先遍历
广度优先遍历又称为按层遍历,可以借助FIFO特征的队列来实现
- 建立一个队列(先进先出),把树的根节点压入队列
- 从队列中弹出一个节点,然后把该节点的左,右节点压入队列,如果没有子节点,则说明已经到达叶子节点了
- 用循环重复执行第2步,知道队列为空。当前队列为空时,说明所有的叶子节点,都已经经过了队列,也就完成了遍历
//广度优先遍历
public List<TreeNode> breadthFrist()
{
Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
List<TreeNode> list = new ArrayList<TreeNode>();
if(root!=null)
{
//将根元素加入队列
queue.offer(root);
}
while(!queue.isEmpty())
{
//将该队列的队尾的元素添加到List中
list.add(queue.peek());
TreeNode p = queue.poll();
//如果左子节点不为null,将它加入队列
if(p.left!=null)
{
queue.offer(p.left);
}
//如果右子节点不为null,将它加入队列
if(p.right!=null)
{
queue.offer(p.right);
}
}
return list;
}