Function
1.方法的重载
名字必须相同但参数列表必须不相同
加了包以后编译出错的解决方案
2.可变参数
可变参数必须要在所有参数的最后面
3.递归
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S05d2NNi-1687312409321)(C:/Users/NM/AppData/Roaming/Typora/typora-user-images/image-20230130173313250.png)]
Demo:阶乘
package com.xx.function;
import java.util.Scanner;
public class Demo02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数:");
int number = scanner.nextInt();
System.out.println(number+"的阶乘为:"+f(number));
}
public static int f(int n) {
if (n == 1) {
return 1;
} else {
return n * f(n - 1);
}
}
}
程序执行过程
注意点:对于递归调用,一定要写明其结束的条件,否则程序会无限的进行调用,会不断占用栈的资源
5.Array
数组在内存里面的变化
1.内存分配
- 堆:存放对象实例和数组
- 栈:基本数据类型和对象的引用
- 方法区:类、静态方法、静态变量、常量、成员方法、常量池
2.冒泡排序
//冒泡排序
//对数组中相邻的两个数进行比较,每次比较找出最大值或者最小值
public static int[] bubbleSort(int[] number) {
int temp;
//外层循环表示比较的轮数
for (int i = 0; i < number.length - 1; i++) {
// System.out.println(number[i]);
//内循环表示比较次数 每一轮都会出现一个最大值和最小值
for (int j = 0; j < number.length - 1 - i; j++) {
if (number[j] > number[j + 1]) {
temp = number[j];
number[j]= number[j+1];
number[j+1]=temp;
}
}
}
return number;
}
}
3.稀疏数组
package com.xx.array;
public class Demo02 {
/**
* ROW:行
* COLUMN:列
*/
final static int ROW = 11;
final static int COLUMN = 11;
public static void main(String[] args) {
int[][] array = new int[ROW][COLUMN];
array[1][2] = 1;
array[2][3] = 2;
System.out.println("原始数组:");
printArray(array);
int[][] result = sparseArrays(array);
System.out.println("稀疏数组:");
printArray(result);
}
/**
* 打印数组
*
* @param array
*/
public static void printArray(int[][] array) {
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
System.out.print(array[i][j] + "\t");
}
System.out.println();
}
}
public static int[][] sparseArrays(int[][] array) {
//获取有效值的个数
int value = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (array[i][j] != 0) {
value++;
}
}
}
int[][] sparse = new int[value + 1][3];
sparse[0][0] = ROW;
sparse[0][1] = COLUMN;
sparse[0][2] = value;
//计数
int count = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (array[i][j] != 0) {
count++;
sparse[count][0] = i;
sparse[count][1] = j;
sparse[count][2] = array[i][j];
}
}
}
return sparse;
}
}
OOP
本质:以类的方式组织代码,以对象的组织(封装)数据
特性:封装、继承、多态
1.构造器
在创建一个对象的时候,会默认的去创建一个无参构造
2.内存图分析
3.继承(extends、Super)
4.重写
需要继承关系,子类重写父类的方法!
-
方法名必须相同
-
参数列表必须相同
-
方法体可以不同
-
修饰符:范围可以扩大,不能缩小;常见:public>protected>default>private
重写的原因:父类的功能,子类不一定需要,或者不一定满足
5.多态
- 一个类实际类型可以确定,但是引用类型是变化的
注意点
1.多态是方法的多态,属性没有多态
2.父类和子类,有联系
3.存在条件:继承关系,方法需要重写,父类引用指向子类对象
- static方法 不能重写,它是属于类的
- final
- private修饰的方法
6.static
和类一块加载
静态代码块
- 执行顺序:静态代码块、匿名代码块、构造方法
- 今天代码块只执行一次
7.抽象类(abstract)
- 抽象方法:只有名字,没有实现的细节。抽象类的所有方法,子类都要实现
- 抽象类不能创建,只能子类来实现
- 抽象类里面的方法不一定为抽象方法,但是抽象方法一定要在抽象类里面
8.接口(interface)
- 接口都要有实现类(implements)
- 接口可以实现多继承
- 实现接口,要重写接口的方法
- 接口中的所有方法都是抽象的,都是public修饰的
- 接口中定义的变量,通常为常量
9.Exception或Error
- 检查性异常
- 运行时异常
- 错误
异常的捕获:(ctrl+alt+t)
try、catch、finally、throw(方法中)、throws(方法上)
Thread
线程的创建
1.继承Thread类,重写run()方法,开启start()
package com.xx.Thread;
/*
线程的创建方式一:
继承Thread类,重写run方法,开启start,执行的顺序由cpu的调度安排
*/
public class TestThread01 extends Thread {
//重写run方法
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run线程" + i);
}
}
public static void main(String[] args) {
//创建线程
TestThread01 testThread01 = new TestThread01();
//开启线程
testThread01.start();
for (int i = 0; i < 1000; i++) {
System.out.println("main线程" + i);
}
}
}
图片下载
package com.xx.Thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//图片下载
public class TestThread02 extends Thread {
private String url;
private String name;
//构造器传递路径和名字
public TestThread02(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownload webDownload = new WebDownload();
webDownload.download(url, name);
System.out.println(name+"下载完成");
}
public static void main(String[] args) {
TestThread02 t1 = new TestThread02("https://cn.bing.com/images/search?view=detailV2&ccid=wc%2fdCG%2fK&id=2A67B025EDB55DFCC3EACFBF5B0CD513CC71AE39&thid=OIP.wc_dCG_KbIKZwMdtD3gL2QHaEt&mediaurl=https%3a%2f%2fpic3.zhimg.com%2fv2-58d652598269710fa67ec8d1c88d8f03_r.jpg%3fsource%3d1940ef5c&exph=1304&expw=2048&q=%e5%9b%be%e7%89%87&simid=607986392537319467&FORM=IRPRST&ck=7906E4DE8F66609504206A4E0B045F1E&selectedIndex=1", "01.jpg");
TestThread02 t2 = new TestThread02("https://cn.bing.com/images/search?view=detailV2&ccid=YQ6LnR6c&id=9B613B6C54487D383AB606CCC723D63A20A6211C&thid=OIP.YQ6LnR6cs5xapSK8o0wChwHaEo&mediaurl=https%3a%2f%2fdesk-fd.zol-img.com.cn%2ft_s960x600c5%2fg1%2fM0B%2f03%2f06%2fChMljl402K6IOTZbAARWayFg6S4AAQJPwFhuRIABFaD752.jpg&exph=600&expw=960&q=%e5%9b%be%e7%89%87&simid=608041587144007854&FORM=IRPRST&ck=AD2923F3F781869FBFA5AAC4B03EB411&selectedIndex=3&ajaxhist=0&ajaxserp=0", "02.jpg");
TestThread02 t3 = new TestThread02("https://cn.bing.com/images/search?view=detailV2&ccid=YKoZzgmu&id=702E280C47E9987874D231029BBBC2628E1A46C2&thid=OIP.YKoZzgmubNBxQ8j-mmoTKAHaEK&mediaurl=https%3a%2f%2fpic.3gbizhi.com%2f2019%2f0928%2f20190928012439343.jpg&exph=2592&expw=4608&q=%e5%9b%be%e7%89%87&simid=607999298888101361&FORM=IRPRST&ck=4BC2A0E29300968C1CE49D200C16DF25&selectedIndex=7&ajaxhist=0&ajaxserp=0", "03.jpg");
t1.start();
t2.start();
t3.start();
}
}
//下载器
class WebDownload {
public void download(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载器异常");
}
}
}
工具类下载链接:(20条消息) 如何优雅地下载和使用Apache Commons_io_我想脱离小码农的博客-CSDN博客
2.实现Runnable接口
package com.xx.Thread;
public class TestThread03 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run线程" + i);
}
}
public static void main(String[] args) {
//创建Runnable实现类
TestThread03 thread03 = new TestThread03();
//实现Runnable接口
new Thread(thread03).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main线程" + i);
}
}
}
龟兔赛跑
package com.xx.Thread;
import sun.awt.windows.ThemeReader;
//龟兔赛跑
public class Race implements Runnable{
private static String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//判断比赛是否结束
boolean flag = gameOver(i);
//兔子休息
if(Thread.currentThread().getName()=="兔子" && i%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (flag) {
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
//是否完成比赛通过判断是否存在胜利者来判断
public boolean gameOver(int steep){
if (winner!=null){//存在胜利者
return true;
}else if (steep>=100){
winner = Thread.currentThread().getName();
System.out.println("Winner is "+winner);
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"乌龟").start();
new Thread(race,"兔子").start();
}
}
3.实现Callable接口
4.Lamda表达式
- 函数式接口:接口里面只含有一个抽象方法
- 函数式接口才能使用Lamda表达式
- lambda表达式只有一行代码的情况下,可以去掉花括号,否则就要用其包裹
- 多个参数也可以去掉,但是必须要加()
package com.xx.Thread;
public class Lamda {
public static void main(String[] args) {
Person p = (a)-> System.out.println("aa"+a);
p.stuent(7);
}
}
interface Person{
void stuent(int a);
}
5线程的生命周期
创建–>就绪–>(阻塞)–>运行–>死亡
线程停止(利用标志位实现)
package com.xx.Thread;
//通过标志位来停止线程
public class TestStop implements Runnable {
//标志位
private boolean flag = true;
@Override
public void run() {
int j = 0;
while (flag) {
System.out.println("Thrad....run" + j++);
}
// System.out.println("Thread");
}
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
// System.out.println("main"+i);
if (i == 900) {
testStop.stop();
// System.out.println("Stop");
}
}
}
}
6.Sleep、yield、State、Damon
模拟网络延时:放大问题的发生性
模拟倒计时
sleep不会释放线程锁
线程守护:用户线程、守护线程(一般情况都为用户线程)
7.线程同步
同步方法
同步代码块
package com.xx.Thread;
public class Bank {
public static void main(String[] args) {
Account account = new Account(1000, "存款");
Drawing my = new Drawing(account, 500, "my");
Drawing wife = new Drawing(account, 400, "wife");
my.start();
wife.start();
}
}
//账户
class Account {
//余额
private int money;
//卡名
private String name;
public Account(int money, String name) {
this.money = money;
this.name = name;
}
public int getMoney() {
return money;
}
public String getName() {
return name;
}
public void setMoney(int money) {
this.money = money;
}
public void setName(String name) {
this.name = name;
}
}
//银行
class Drawing extends Thread {
//账户
Account account;
//取走了多少钱
int drawing;
//手里多少钱
int nowMoney;
public Drawing(Account account, int drawing, String name) {
super(name);
this.account = account;
this.drawing = drawing;
}
//取钱
@Override
public void run() {
//锁的对象为变化的量
synchronized (account) {
//判断是否有钱
if (account.getMoney() - drawing < 0) {
System.out.println(Thread.currentThread().getName() + "没钱了");
return;
}
//模拟网络延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡里的钱
account.setMoney(account.getMoney() - drawing);
//手里的钱
nowMoney = nowMoney + drawing;
//账户余额为
System.out.println(account.getName() + "账户余额为" + account.getMoney());
//手里的钱
System.out.println(this.getName() + "手里的钱为" + nowMoney);
}
}
}
lock锁
8.线程通信
生产者消费者问题
管程法
package com.xx.Thread;
//线程通信 管程法 (生产者,消费者问题)
public class TestPc {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Producer(synContainer).start();
new Consumer(synContainer).start();
}
}
//生产者
class Producer extends Thread {
//缓冲区
SynContainer synContainer;
public Producer(SynContainer synContainer) {
this.synContainer = synContainer;
}
//生产
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.push(new Product(i));
System.out.println("生产了第" + i + "个产品");
}
}
}
//消费者
class Consumer extends Thread {
SynContainer synContainer;
public Consumer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了第"+synContainer.pop().id+"个产品");
}
}
}
//产品
class Product {
//产品编号
int id;
public Product(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
//容器
Product[] products = new Product[10];
//计数器
int count;
//生产者放入产品
public synchronized void push(Product product) {
if (products.length == count) {
//如果满了,生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//没有满,放入产品
products[count] = product;
count++;
//通知消费者
this.notifyAll();
}
//消费者消费产品
public synchronized Product pop() {
//判断能否消费产品
if (count == 0) {
//消费者等待,生产者生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费产品
count--;
//取出产品
Product product = products[count];
//通知生产者
this.notifyAll();
//返回产品
return product;
}
}
信号灯法
package com.xx.Thread;
//信号灯法
public class TestPC2 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//演员
class Player extends Thread {
TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
//表演20秒
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
tv.play("快了大本营");
} else {
tv.play("广告");
}
}
}
}
//观众
class Watcher extends Thread {
TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//电视
class TV {
//节目
String voice;
//标志位
boolean flag = true;
//演员表演,观众等待 T
//演员等待,观众观看 F
//演员表演
public synchronized void play(String voice) {
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了" + voice);
//通知观众观看
this.notifyAll();
this.voice = voice;
this.flag = !this.flag;
}
//观众观看
public synchronized void watch() {
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观众观看了" + voice);
//通知演员表演
this.notifyAll();
this.flag = !this.flag;
}
}
注解和反射
注解
内置注解
@Override:复写
@Deprecated:方法已经废弃,不推荐使用
@SuppressWarnings(“”):镇压警告
元注解
@Target:注解使用的范围
@Retention:注解的生命周期(SOURCE<CLASS<**RUNTIME**)
@Document:该注解包含在javadoc中
@Inherited:用于子类可以继承父类
反射
一个类在内存中只有一个class对象
一个类被加载后,类的整个结构都会被封装在Class对象中
获取Class的方式
User user = new Student();
System.out.println("当前用户为"+user);
//方式一:通过对象获得
Class c1 = user.getClass();
System.out.println(c1.hashCode());
//方式二:通过forName()获得
Class c2 = Class.forName("com.xx.reflection.Student");
System.out.println(c2.hashCode());
//通过类名.class获得
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本类型的包装类都有一个Type属性
Class<Integer> c4 = Integer.TYPE;
System.out.println(c4.hashCode());
//获取父类属性
Class c5 = c1.getSuperclass();
所有类型的Class
//Object类
Class<Object> c1 = Object.class;
//接口
Class<Comparable> c2 = Comparable.class;
//一维数组
Class<String[]> c3 = String[].class;
//二维数组
Class<int[][]> c4 = int[][].class;
//注解
Class<Override> c5 = Override.class;
//枚举
Class<ElementType> c6 = ElementType.class;
//void
Class<Void> c7 = void.class;
//基本数据类型
Class<Integer> c8 = int.class;
//Class
Class<Class> c9 = Class.class;
类的加载
类的初始化
类加载器
package com.xx.reflection;
/**
* 类加载器
*/
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取系统加载器的父类加载器-->扩展类加载器.
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//获取扩展类加载器的父类加载器-->根加载器(C/C++)
ClassLoader parentParent = parent.getParent();
System.out.println(parentParent);
//测试当前类是那个加载器(通过反射)
ClassLoader classLoader = Test03.class.getClassLoader();
System.out.println(classLoader);
//测试JDK内置的类是谁加载的
ClassLoader loader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(loader);
//获取系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));//根加载器
/**
* 双亲委派机制
* 自己定义的类要加载,会先去用户类寻找是否有这个包,如果没有再去扩展类
* 加载器去寻找,如果没有就会根加载器寻找
* 双亲委派机制,多重检测,保证安全性
*/
}
}
获取类的信息
package com.xx.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 获取类的信息
*/
public class Test04 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
//反射获得Class
Class<User> userClass = User.class;
//获得类的名字
//包名+类型
System.out.println(userClass.getName());
//简单类名
System.out.println(userClass.getSimpleName());
//获得类的属性
/**
* userClass.getFields(); 获得公共属性
* userClass.getDeclaredFields(); 获得所有属性
*/
for (Field field : userClass.getDeclaredFields()) {
System.out.println(field);
}
//获得指定属性
System.out.println(userClass.getDeclaredField("name"));
//获得类的方法
/**
* userClass.getMethods(); 获得本类及其父类的全部public方法
* userClass.getDeclaredMethods(); 获得本类的所有方法
*/
for (Method method : userClass.getDeclaredMethods()) {
System.out.println(method);
}
//获得指定方法
//获取方法的时候,除了写明方法名,还要写明方法的参数类型
System.out.println(userClass.getDeclaredMethod("getName", null));
//获取构造器
for (Constructor<?> constructor : userClass.getDeclaredConstructors()) {
System.out.println(constructor);
}
//获得指定的构造器
System.out.println(userClass.getDeclaredConstructor(String.class, int.class, int.class));
}
}
通过反射创建对象并操作属性和方法
package com.xx.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test05 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class<User> userClass = User.class;
//构造一个对象 使用newInstance创建对象 使用的是无参构造器
User user = userClass.newInstance();
System.out.println(user);
//通过构造器创建对象
Constructor<User> constructor = userClass.getDeclaredConstructor(String.class, int.class, int.class);
User user1 = constructor.newInstance("张三", 001, 18);
System.out.println(user1);
//通过反射调用方法
User user2 = userClass.newInstance();
//通过反射获取一个方法
Method setName = userClass.getDeclaredMethod("setName", String.class);
//invoke:激活 参数(对象,"方法值")
setName.invoke(user2, "zhangsan");
System.out.println(user2.getName());
//通过反射操作属性
//对于属性,我们不能直接操作私有的属性,它存在安全检测,可以通过seAccessible(true)关闭
User user3 = userClass.newInstance();
Field name = userClass.getDeclaredField("name");
name.setAccessible(true);
name.set(user3,"李四");
System.out.println(user3.getName());
}
}
newInstance():创建的对象使用的是无参构造器
私有化的方法和属性要使用setAccessible(true),不然就会报错
在性能上,反射创建对象的性能没有new的高
反射获取泛型
package com.xx.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class Test06 {
public static void test01(Map<String, User> map, List<Integer> list) {
System.out.println("test01");
}
public static Map<String, User> test02() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//通过反射获取方法
Method method = Test06.class.getDeclaredMethod("test01", Map.class, List.class);
//获取方法的参数类型
/**
* getGenericParameterTypes:返回Type类型的数组 Type[].
* getParameterTypes:返回Class类型的数组: Class<?>[].
*/
Type[] types = method.getGenericParameterTypes();
for (Type type : types) {
System.out.println(type);
//判断type类型是否属于参数化类型
if (type instanceof ParameterizedType) {
//将type类型转化为参数化类型并且获得它真实类型的数组
for (Type actualTypeArgument : ((ParameterizedType) type).getActualTypeArguments()) {
System.out.println(actualTypeArgument);
}
}
}
//获取返回值类型
Method methods = Test06.class.getDeclaredMethod("test02",null);
Type genericReturnType = methods.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType){
for (Type actualTypeArgument : ((ParameterizedType) genericReturnType).getActualTypeArguments()) {
System.out.println(actualTypeArgument);
}
}
}
}
getGenericParameterTypes和getParameterTypes区别:https://blog.csdn.net/u013066244/article/details/102997214
通过反射获得注解
package com.xx.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.xx.reflection.Students");
//获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value值
TableStudent annotation = (TableStudent)c1.getAnnotation(TableStudent.class);
String name = annotation.name();
System.out.println(name);
// TableStudent tablemi = (TableStudent)c1.getAnnotation(TableStudent.class);
// String value = tablemi.value();
// System.out.println(value);
//获得属性的注解
//获得属性
Field name1 = c1.getDeclaredField("id");
FieldStudent annotation1 = name1.getAnnotation(FieldStudent.class);
System.out.println(annotation1.columnName());
}
}
@TableStudent(name = "db_student")
class Students{
@FieldStudent(columnName = "db_id",type = "int",length = 10)
private int id;
private String name;
private int age;
public Students() {
}
public Students(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableStudent{
String name();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldStudent{
String columnName();
String type();
int length();
}