一、eclipse工具的使用
eclipse是一个开源的IDE,进行javaEE开发一般使用myeclipse插件比较方便
1. java代码的位置
1) 选择工作空间 workspace
选择一个文件夹存放程序(代码) 不要用中文和空格
2) 新建一个java 工程(Project)
3) 建包(Package) 建类(Class)
在 new 菜单下可以选择新建工程、包、类、接口等
2. 快捷键
alt + / : 代码自动补齐,需要配置的
打开preferences(首选项), 搜keys,打开快捷键配置面板
搜 alt+/ ,取消绑定
搜 content assist ,取消原先的绑定,配置成alt+/
ctrl+1: 错误自动修复, 注意,放行的红叉是可修复的,圆形的是不可修复的
导包的三种方式:
1)将类名敲完整,按下alt+/ 进行补齐,会自动导包
2) ctrl+1,修正错误
3) ctrl+shift+o 整理包,导入需要的包,去掉多余的导包语句
ctrl+shift+f : 代码格式化
管理透视图: 在 window 菜单下可以对透视图进行管理
ctrl+2,L 自动声明变量 先按下ctrl+2 再按下 L
shift+enter 光标直接进入下一行
ctrl+alt+方向键(向上向下) 复制行
alt+ 方向键(向上向下) 移动当前行
3. 断点调试
两个用法
1. 程序出错了
Step1:从上至下,找到一个行我们自己写的代码,点击超链接查看代码
Step2:在这行代码前面加断点,用断点方式来运行程序,通过查看变量的方式来确定错误
2. 使用断点方式查看源代码
1) 可以对程序进行调试
在行的开头双击左键打断点,用debug方式来运行程序,程序就会停留在断点位置
F5 跳入(step into) 跳入方法内部 F6 跳过, 让当前行运行 F7跳出 返回上一层程序
resume 直接运行到下一个断点
2) 查看源代码建议使用断点调试的方式,注意当前运行环境需要包含源码
4. junit单元测试
1) 写一个java类,作为测试类
声明测试方法,修饰符为 public static void ,
在方法前面加注解,(@Test) 就可以讲方法教给junit来运行
2) 需要在测试方法前做初始化工作
写一个方法 public void init()
在方法前加注解 @Before
3) 需要在测试后释放资源
写一个方法
在方法前加注解 @After
4) 断言
用于对测试的结果下断言,将实际结果和预期结果进行比较
org.junit.Assert 用于在测试用例中下断言,如果断言失败,程序将不会继续执行
二、jdk5新特性
java 1995 诞生, 版本: jdk1.0—jdk1.1 – jdk1.2 – jdk1.3 –jdk1.4 – 2005老虎版 jdk5.0 – jdk6 -- jdk7
三个平台: javase javaee
1. 静态导入
1) 导入类的静态属性
import static java.lang.System.out;
out.println("haha");
2) 导入类的静态方法
import static java.lang.Math.*; // 导入Math类的所有静态成员
int num = abs(-10);
2. 基本数据类型的包装类
在 java 中,所有的事物都被看做对象,包括一个数字
int --> Integer
byte --> Byte
short --> Short
long --> Long
char --> Character
double --> Double
float --> Float
boolean --> Boolean
1) Integer x = 1; x = x + 1; 经历了什么过程? 装箱à 拆箱 à 装箱
2) 为了优化,虚拟机为包装类提供了缓冲池, Integer池的大小 -128~127 一个字节的大小
3) String池
Java为了优化字符串操作 提供了一个缓冲池
面试题:
String s = “abc” 和 String s = new String(“abc”) 的区别
String s = new String(“abc”) 创建了几个对象 2个
String s = “a” + “b” + “c” + “d” 创建了几个对象
String s1 = “a” String s2 = “b” String s3 = s1 + s2; s3==”ab”?
/*1. String s = "abc", 虚拟机首先会检查String池里有没有"abc"对象(通过equals方法)
// 如果有,直接返回引用,如果没有,会在池里创建一个“abc”对象,并返回引用
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2); // result: true
*/
/* 2. String str = new String("abc");
不管缓冲池是否有"abc", 都会在堆内存创建一个"abc"对象,返回引用
// 此时,负责检查并维护缓冲池,其实堆内存的对象是缓冲池中"abc"对象的一个拷贝的副本
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1==s2); // result: false
*/
/* 3. String s = "a" + "b" + "c" + "d"; java编译器有个合并已知量的优化功能
// 在编译阶段就把"a" + "b" + "c" + "d" 合并为 ”abcd“
String s = "a" + "b" + "c" + "d";
// String s = "abcd";
System.out.println(s=="abcd");// result: true
*/
/* 4. String s1 = "a"; String s2 = "b"; String s3 = s1 + s2;
// String是常量,不能相加的,java如何实现的? StringBuffer
StringBuilder sb = new StringBuidler(s1);
sb.append(s2);
s3 = sb.toString();
也就是说实际上s3是方法返回的String对象
凡是方法返回的字符串对象都是在堆内存的 副本
*/
String s1 = "a";
String s2 = "b";
String s3 = s1 + s2; // 堆内存的对象
System.out.println(s3=="ab");// result: false
3. 增强for循环
1) 作用:
对存储对象的容器进行迭代
2) jdk5以前怎么迭代
3) 增强for循环迭代数组
String [] arr = {"a", "b", "c"}; //数组的静态定义方式,只试用于数组首次定义的时候
// 传统方式
for(int i=0; i<arr.length; i++) {
// i依次表示数组的角标
String s = arr[i];
System.out.println(s);
}
System.out.println("-------------------------------------");
// 在jdk5中我们可以使用增强for循环迭代
// 增强for循环括号里写两个参数,第一个是声明一个变量,变量类型必须是数组元素的类型
// 第二个就是需要迭代的容器
// for循环会循环容器的length次, 每次都将容器的第n-1个元素赋值给声明的变量
for(String s : arr) {
// 循环体, 执行arr.length
// 每次都将arr中的第n-1个元素给s
System.out.println(s); //
}
4) 单列集合 Collection
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
// 传统方式1
/* 1.获得迭代器
Iterator iter = list.iterator();
// 2.循环判断迭代器是否有下一个
while(iter.hasNext()) {
String str = (String) iter.next(); // 将迭代器的指针移向下一个,并将迭代当前指向的元素返回
System.out.println(str);
}
*/
// 传统方式2
for(Iterator iter=list.iterator(); iter.hasNext(); ) {
String s = (String) iter.next();
System.out.println(s);
}
System.out.println("--------------------------------");
// 增强for循环, 没有使用泛型的集合能不能使用增强for循环迭代?能
for(Object obj : list) {
String s = (String) obj;
System.out.println(s);
}
5) 双列集合 Map
Map map = new HashMap();
map.put("a", "aaa");
map.put("b", "bbb");
map.put("c", "ccc");
// 传统方式迭代1
// 1. 获得所有的key
Set keys = map.keySet();
// 2.迭代keys获得所有的key
Iterator iter = keys.iterator();
while(iter.hasNext()) {
String key = (String) iter.next(); // a b c
// 3.根据key获得对应的value
String value = (String) map.get(key);
System.out.println(key + "=" + value);
}
System.out.println("---------------------------------");
// 传统方式2,必须掌握这种方式
// 1.获得所有的键值对Entry对象
Set entrys = map.entrySet();
// 2.迭代出所有的entry
iter = entrys.iterator();
while(iter.hasNext()) {
Map.Entry entry = (Entry) iter.next();
// 分别获得key和value
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("-------------------------------------");
System.out.println("增强for循环迭代,");
// 增强for循环迭代,
// 原则上map集合是无法使用增强for循环来迭代的,
// 因为增强for循环只能针对实现了Iterable接口的集合进行迭代
// Iterable是jdk5中新定义的接口,就一个方法iterator方法
// 只有实现了Iterable接口的类,才能保证一定有iterator方法
// java有这样的限定是因为增强for循环内部还是用迭代器实现的
// 而实际上,我们可以通过某种方式来使用增强for循环
for(Object obj : map.entrySet()) {
// obj 依次表示Entry
Map.Entry entry = (Entry) obj;
System.out.println(entry.getKey() + "=" + entry.getValue());
}
6)集合迭代注意问题
// 在使用迭代器迭代集合的过程中,不能对集合进行增删操作
@Test
public void test4() {
List list = new ArrayList();
list.add("wangwu");
list.add("zhangsan");
list.add("lisi");
Iterator iter = list.iterator();
while(iter.hasNext()) {
String name = (String) iter.next();
if("wangwu".equals(name)) {
// 从集合中删掉
//list.remove(name);
// 迭代过程中删除元素需要调用迭代器的方法
iter.remove(); // 删除我迭代的集合被我迭代的最后一个元素
}
}
// 1 2 4
System.out.println(list.size());
}
@Test
public void test5() {
List list = new ArrayList();
list.add("aa");
list.add("bb");
// 使用ListIterator迭代器
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()) {
listIterator.next();
// 迭代过程中增加元素
listIterator.add("cc");
}
System.out.println(list.size());
}
7) 增强for循环注意问题
//在使用增强for循环时,不能对元素进行赋值
int[] arr = {1,2,3};
for(int num : arr) {
num = 0;
}
System.out.println(arr[1]);
4. 可变参数
1) jdk5中方法的形参可以定义为可变参数,传入实参个数可变
// 设计一个方法求n个数的和
public static int getSum(int... arr) {
// 可变参数在方法中仍被看做一个数组
int sum = 0;
for(int num : arr)
sum += num;
return sum;
}
2)Arrays.asList为例演示传入不同参数的情况
代码演示1
// list长度为3
List list = Arrays.asList("a","b","c");
// list长度为1, 因为考虑1.4语法
String[] arr = {"a","b","c"};
List list = Arrays.asList(arr);
// 同时符合1.4和1.5的语法,此时会优先考虑1.4的语法
// 原因是有了新功能要保证以前的代码不出错,向后兼容
// 现在就需要将arr作为一个元素存入集合
Object obj = arr;
List list2 = Arrays.asList(obj); // 此时只符合1.5的语法,不符合1.4的语法,没有歧义
List list3 = Arrays.asList(new Object[]{arr}); // 优先考虑1.4,所以数组会拆开
//System.out.println(list3.size());
// 基本数据类型数组只符合1.5的语法
int[] nums = {1,2,3};
list = Arrays.asList(nums);
System.out.println(list.size());
代码演示2
//List list = Arrays.asList("a","b","c");
String[] arr = {"a","b"};
List list = Arrays.asList(arr); // 按照1.4语法理解,取出数组的元素存入集合 按照5.0的语法理解,将数组直接存入集合
// 当版本出现歧义时, 虚拟机会优先考虑 低版本的 向下兼容
// List list1 = Arrays.asList((Object)arr);
List list1 = Arrays.asList(new Object[]{arr });
System.out.println(list);
System.out.println(list1.size());
int[] nums = {1,2,3,4};
List list3 = Arrays.asList(nums); // 只符合1.5的语法
System.out.println(list3.size());
5. 枚举
枚举:是java中一种特殊的类型,作为任何一种枚举类型来讲,它的取值都是有限的,是一组取值
问题:对象的某个属性的值不能是任意的,必须为固定的一组取值其中的某一个
解决办法:
1) 在setGrade方法中做判断,不符合格式要求就抛出异常
2) 直接限定用户的选择,通过自定义类模拟枚举的方式来限定用户的输入
写一个Grade类,私有构造函数,对外提供5个静态的常量表示类的实例
3) jdk5中新定义了枚举类型,专门用于解决此类问题
4) 枚举就是一个特殊的java类,可以定义属性、方法、构造函数、实现接口、继承类
//枚举类就是一个java类,也可以声明属性,方法,构造函数
public enum Grade4 {
A("90-100"),B("80-89"),C("70-79"),D("60-69"),E("0-59");
private String value;
private Grade4(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
//枚举类就是一个java类, 也可以继承抽象和实现接口
public enum Grade5 {
// 抽象类不能创建实例对象
A("90-100"){
// new了一个Grade5的子类实例
public String toLocaleString() {
return "优";
}
}
,B("80-89"){
// new了一个Grade5的子类实例
public String toLocaleString() {
return "良";
}
}
,C("70-79"){
// new了一个Grade5的子类实例
public String toLocaleString() {
return "中";
}
}
,D("60-69"){
// new了一个Grade5的子类实例
public String toLocaleString() {
return "差";
}
}
,E("0-59"){
// new了一个Grade5的子类实例
public String toLocaleString() {
return "不及格";
}
};
private String value;
private Grade5(String value) {
this.value = value;
}
public String getValue() {
return value;
}
// 对外提供一个方法,返回枚举的本地信息
// 一个方法不知道如何实现,可以定义为抽象的
public abstract String toLocaleString();
}
l 练习:请编写一个关于星期几的枚举WeekDay,要求:
• 枚举值:Mon,Tue,Wed,Thu,Fri,Sat,Sun 星期一。。。。星期日
• 该枚举要有一个方法,调用该方法返回中文格式的星期。
三、 反射
1. java代码
在 java 语言中最核心的就是代码的运行, 按照面向对象的思想,在调用java代码时往往需要先创建对象,再调用方法, 而写在方法中的即所谓的java 代码
一段java代码在程序运行期间会经历三个阶段: source-->class-->runtime
2. Class 对象
在java中用一个Class对象来表示一个java类的class阶段
Class对象封装了一个java类中定义的成员变量、成员方法、构造方法、类名、包名等
获得class对象的三种方式和区别
// 1. 根据给定的类名来获得 用于类加载
String classname = "cn.itcast.reflect.Person"; // 来自配置文件
Class clazz = Class.forName(classname); // 此对象代表Person.class
// 2. 如果拿到了对象,不知道是什么类型 用于获得对象的类型
Object obj = new Person();
Class clazz1 = obj.getClass(); // 获得对象具体的类型
// 3. 如果是明确地获得某个类的Class对象 主要用于传参
Class clazz2 = Person.class;
// 在java中所有的类型都会对应一个Class对象 int Integer
Class intClazz = int.class;
Class intarrClazz = int[].class;
Class voidClazz = void.class;
3. 反射的概念
反射就是获得一个java类的各个组成部分
// 反射类的成员方法
Class clazz = Person.class;
Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});
method.invoke();
// 反射类的构造函数
Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})
con.newInstance(params...)
// 反射类的属性
Field field = clazz.getField(fieldName);
field.setAccessible(true);
field.setObject(value);
4. 反射用在哪里
到底框架是什么? 框架就是将开发中大量重复的代码集中起来写个通用的程序
框架就是用反射来实现的
框架需要现在的类调用将来写的类
框架是将来的程序员调用的,框架不能实现完整的功能,框架只是一些一些通用的代码
框架要运行一定会依赖将来写的类
现在写的类要调用将来写的类,我们先针对接口进行调用,将来的类需要实现接口,那么方法就固定了
但是将来写的类的类名我们无法获知,这时就需要调用者通过配置文件告诉框架具体的类名
四、泛型
1. 概念
泛型是一种可变化的类型
类型不确定,需要调用者来指定
2. 用途
一个类的多个成员方法用到的参数类型或返回值类型都是未知的类型,但又需要是同一个类型,就可将方法的
参数类型定义为泛型,此泛型必须在类上先予以声明才能在方法中使用
一个方法的多个参数和返回值需要是同一个类型,也可以用泛型来解决,在方法返回值前面声明泛型
3. 细节
1) 泛型到底代表什么类型取决于调用者传入的类型,如果没传,默认是Object类型
2) 使用带泛型的类创建对象时, 等式两边指定的泛型必须一致
原因: 编译器检查对象调用方法时只看变量,然而程序运行期间调用方法时就要考虑对象具体类型了
3) 等式两边可以在任意一边使用泛型 在另一边不使用 (考虑向后兼容)
4. 术语
以List<E>为例:<>念着typeof 例, List<String> 就是 List typeof String
List<E>中的E称为类型参数变量 方法定义参数形式参数
List<Integer>中的Integer称为实际类型参数
整个List<E>称为泛型类型 GenericType
整个List<Integer>称为参数化的泛型类型
5. 使用
1)在集合中,泛型得到了广泛的应用,需要注意以下两个问题
定义集合对象时,等式两边所使用的泛型必须类型一致
等式两边允许只在一边指定泛型
2)使用带泛型的类时,在创建对象时可以为泛型指定实际类型参数,指定的具体类型相当于给泛型传参
3)子类在继承父类的时候,可以为父类定义的泛型指定实际类型参数
class B<T>
class A extends B<String>
通过子类A获得的父类类型就是一个参数化的类型
4)调用方法时传入参数的具体类型将作为方法中泛型的实际类型
五、内省(xing)
1. javabean
Javabean就是拥有一种固定写法的java类,在应用程序中我们使用javabean来封装数据
定义一个javabean需要遵循下面的规定:
1)必须有无参构造函数
2)属性必须私有,我们称为字段
3)提供标准的getter和setter
例: name 字段 的getter: String getName() settter: void setName(String name)
2. 内省
内省: 通过反射的方式访问javabean的属性 Class.forName().newInstance()
传统方式访问javabean都是通过直接调用属性的 getter 和 setter方法完成的,而在一些特殊情况下,无法获知类的方法名是什么,比如要访问将来未写好的javabean
Jdk中提供了api :PropertyDescriptor类用于访问javabean的属性
3.BeanUtils工具包
Apache组织开发了一套用于操作JavaBean的API , 被称为 BeanUtils 组件, 该组件对内省实现了封装
核心类 BeanUtils
setProperty(bean, name, value) 设置javabean的属性
getProperty(bean, name) 访问 javabean 的属性
copyProperties(target, source); 拷贝javabean的属性
可以支持String到8中基本数据类型转换
其他引用数据类型都需要注册转换器 ConvertUtils.register(Converter, Class)
六、内部类
在一个类中定义的类,称为内部类
内部类可以被定义在类或方法中, 在方法中定义的类不能访问方法的局部变量,除非该变量为final的
典型用法: 匿名内部类
调用一个方法时,如果该方法接收的参数为接口类型,此时,需要先用一个类实现该接口,创建该类的实例对象传入该方法,此时,可以采用匿名内部类的方式来解决。
内部类细节:
1. 内部类可以访问外部类的所有成员 外部类类名.this.成员
2. 方法中定义的内部类不能访问方法的局部变量,除非该变量时final的
七、多线程
1. 概念
进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动
线程: 进程的一个实体,是CPU调度和分派的基本单位
一个应用程序可以包含多个进程,但至少会有一个进程,一个进程可以包含多个线程,并至少有一个线程
2. 线程的启动
在程序中启动一个新线程运行一段代码有两种方式
1) 写一个类继承 Thread 类, 重写 run 方法, 调用 start 方法
2) 通过 Thread 类的 start 方法启动线程, 在实例化 Thread 类的时候, 传入一个对象实现 Runnable
3. 线程的同步
多线程并发访问的数据都会有线程安全问题
解决线程安全问题将并发访问的代码加锁,让多个线程同步访问,此过程称为线程的同步
八、socket
1. 网络协议(tcp/ip)
ip协议: 每台计算机都有一个唯一的ip地址作为标识
ipv4 占4个字节,用点号分隔 192.168.1.100
ipv6 占16个字节(为得到广泛使用)
端口号: 每个应用程序都会运行在计算机的唯一端口上 0~65535 建议使用 1024 以上的
tcp协议:
传输控制协议,面向连接,提供可靠无差错的协议,安全,三次握手
Jdk 中对tcp协议实现了封装
核心api为 ServerSocket Socket
九、注解
1. jdk中自带的三个注解
@Deprecated 声明方法已过时
@SuppressWarnings 取消编译器警告
@Override 声明方法是继承自父类
2. 什么是注解
注解就是java代码中的特殊标记,它用于告诉调用者类应该如何被运行
注解相当于配置文件的功能
3. 自定义注解
使用 @interface 关键字可以声明一个注解
public @interface MyAnnotation1
注解中可以定义属性
String name default “aaa”;
value是注解中的特殊属性
注解中定义的属性如果名称为 value, 此属性在使用时可以省写属性名
4.元注解 元Annotation
元注解简单理解为 注解的注解
类似于描述一个注解的信息的配置文件
@Retention 指定注解的作用域
RetentionPolicy.SOURCE
RetentionPolicy.CLASS default
RetentionPolicy.RUNTIME
@Target:指定注解用于修饰类的哪个成员.
@Target 包含了一个名为 value,类型为ElementType的成员变量。
@Inherited: 被它修饰的 Annotation 将具有继承性.
如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
5. 反射注解
在程序可以通过反射来获取注解中封装的值
注解的用法: 在类或方法上声明注解,封装一些配置信息,调用者通过读取类或方法上的注解就可以知道如何使用类或方法。
十、动态代理
包装设计模式(装饰模式)
回顾BufferedInputStream(包装类),FileInputStream读取数据的时候是一个字节一个字节的读取,效率很低,确实实现了读取文件。 需要对 FileInputStream 进行包装, 提高读取效率,BufferedInputStream就是这样的包装类, 内置了缓冲区
BufferedInputStream称为包装类 FileInputStream称为被包装对象
1. 包装类要和被包装的对象实现同样的接口
2. 包装类要持有一个被包装对象
3. 包装类在实现接口的时候,对于不需要包装的方法调用被包装对象的方法来实现,对于需要包装的方法,我们自己实现
我们可以为某一个对象生成一个代理对象
代理对象要和被代理的对象实现同样的接口
代理对象的方法被调用时,我们可以做一些动作,再去调用真正被代理对象的方法
在代理对象中对用户的权限进行检查
所有的过滤器都可以用代理模式来解决