Java复习——从入土到入门
Java知识点概览:
Java的概念和特点:
概念
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点, 还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。
由上述介绍可知:
1. Java是一门面向对象的语言
2. Java是单继承的
3. Java语法没有指针概念
特点
Java还有几个重要特点:
1. Java是类型安全的
2. Java是跨平台的
Java的JVM、JRE、JDK
Java的跨平台性是区别于其他语言的显著特点:
Java程序运行在JVM(Java虚拟机)上,我们写的Java源代码通过javac命令编译成.class字节码文件,这个字节码文件可以在各个平台的JVM环境上运行。
Java运行环境(JRE):光有JVM是不够的,Java还需要依赖一些类库,这些类库存在于JRE中,所以JRE包括两部分:JVM和类库
Java开发工具包(JDK):作为开发人员,我们需要编译、调试Java程序,例如javac就存在于JDK中。
所以,想要运行Java程序,借助JRE这个运行环境即可,而开发Java程序,需要JDK这个开发工具包。
Java基本语法
数据类型
Java的数据类型大体上可以分为2种:
1. 基本数据类型
2. 引用数据类型
基本数据类型:
和C语言类似:Java也有整型、浮点型之分,除此之外,Java还多了一种更小的整型:byte型,还有一种表达真假的、仅有两个值的数据类型:boolean
基本数据类型一共有4类,8种:
1. 整型:byte、short、int、long
2. 浮点型:float、double
3. 字符型:char
4. 布尔型:boolean
引用数据类型:
除了基本数据类型外,Java中的各种对象称为引用数据类型
引用数据类型主要有:
1. 数组
2. 类:Class
3. 接口:Interface
4. 注解:Annotation(一种特殊的接口)
我们常用的引用类型有数组(int[]整型数组,char[]字符型数组,甚至Person[]对象数组)、类(例如上面提到的String字符串类)和接口(内含抽象方法)。
程序结构
分支
分支结构主要有:
1. if
2. else
3. else if
4. switch…case
值得注意的是:else总是与最近的if配对
循环
循环结构主要有:
1. while循环
2. do…while循环
3. for循环
三种循环均可以互相转换,do…while循环至少会执行一次
结束本次循环,继续下次循环continue关键字,直接结束掉循环体break关键字
数据的输入与输出
数据输入
利用Scanner类,或利用文件操作相关的类
常用写法:Scanner sc = new Scanner(System.in)
数据输出
利用System类的输出流静态变量out下的多种print()方法,或利用文件操作相关的类
常用写法:System.out.println()
Java的面向对象
简介
所谓的面向对象,是相对于面向过程(C语言)而言的。
例如:我们需要把一个字符串”china”转化为大写字母:
面向过程的思想是利用循环,分别对每一个字符的ASCII码进行处理(因为小写字母和大写字母的ASCII码存在特定的联系)
而面向对象的思想中,我们不关心具体怎么处理,而是利用一个能够处理小写转为大写的对象来处理:
例如String类的toUpperCase()方法,就能把该字符串对象转换为大写字母
上面提到的String类是JDK的Java大神写好的类,类中有很多有用的方法,除了大小写转换外,还有split()分割字符串、substring()截取字符串、charAt()返回某个字符的下标位置等等
另外,除了JDK的大神写好的类外,我们也可以自己定义一些类,一旦定义了一个类,就能通过new关键字不断创建这个类的实例,也叫对象。可以说,类是对一个对象共同特征的一种抽取,它只是一个模板,是抽象的;而对象才是类的一个实例,我们的操作一般是通过实例化出来的对象来操作。这一点放在第三章讲。
面向对象思想
封装
封装就是把具有一定共性的属性抽取出来,形成一个模板,我们称之为类(Class),同时,我们对外尽量隐藏内部实现细节,而只提供一个公共接口(非特指interface)访问。这样可以使得程序更容易维护,也加强了安全性。
继承
类(Class)与类之间是可以继承的,但要注意,Java是单继承的,即一个类只有一个直接父类。继承对于子类来说是对父类的扩充,而父类是对子类的抽象。所以子类不但含有父类的内容,也可以新增自己的内容。
例如class Student extends Person
多态
多态是同一个行为具有多个不同表现形式或形态的能力。Java中,可以把一个子类赋值给一个父类。
例如Person stu1 = new Student()
多态是以继承为前提的,并且多态的子类在赋值给父类时,相当于把子类当作父类使用,即此时的子类特有属性和方法被隐藏起来了。我们可以利用强制类型转换把一个多态写法中当成父类使用的子类对象重新转换为子类。
例如(Student)stu1把Person类型的对象stu1重新转为子类Student,转为子类后的stu1对象被屏蔽掉的特有属性和方法可以使用了。
但是要注意,不能把一个本来就不是子类的对象转为子类
例如:
1 | Person stu2 = new Person(); |
类中的成员
成员变量
成员变量在类中仅作声明,实际上在类实例化成一个对象时才会初始化和分配空间。
定义成员变量:
1 | class Person{ |
成员变量可用权限修饰符修饰:public、protected、不写(default)、private
成员方法
成员方法类似于C语言的函数(function),在Java中,它叫方法(method),用来实现某种操作。
定义成员方法:
1 | class Person{ |
同样的,成员方法也可用权限修饰符修饰:public、protected、不写(default)、private
静态变量
又叫类变量,静态变量是用static修饰的变量,此时这个变量不属于某个具体对象,而是属于类,直接利用类名.静态变量名使用。对它的修改会影响所有用到静态变量的地方。因为它在内存中只保存了一份,任何用到它的地方都指向唯一的地址(存在于静态方法区中)。
静态方法
同样的,静态方法又叫类方法,是用static修饰的方法,此时这个方法也不属于某个具体对象,而是属于类,直接利用类名.静态方法名调用方法。
值得注意的是,在静态方法中不能调用非静态变量(包括this关键字),因为静态方法会先于对象创建,此时静态方法内的非静态变量(实例变量)还没有被初始化,因为对象创建时才会初始化那些实例变量。
静态代码块
形如:
1 | static { |
这样的代码块叫做静态代码块,它会在类初始化之前执行一次,且只会执行一次。如果一个类中有多个静态代码块,那么会从上到下依次执行一次,且只会执行一次。
构造方法和对象的初始化
构造方法
构造方法是类中特殊的方法,用于初始化一个类,在创建对象(实例化一个类为对象)时调用。
特点是:
1. 没有返回值,void也不能写。
2. 名称与类名相同
3. 如果不写,类中会默认隐式声明一个无参构造。一旦定义了一个构造方法,将不会隐式声明其他构造方法。
4. 可以有多种重载形式
5. 在继承关系中,子类会默认调用父类的无参构造,形如:super(),并且只能写在方法的第一行。
6. 可以利用this()调用其他重载的构造方法,但是不能形成递归,否则会造成栈溢出异常(StackOverflowException)。并且this()也只能写在方法的第一行。可见,this()和super()不可能在同一个构造方法中同时出现(因为这两句话都要求写在第一行,显然这是不可能的)。
对象的初始化
静态代码块会在第一次使用到该类时执行,静态变量也会随之初始化。
在使用new 构造方法()初始化一个对象时,会执行该类的构造方法来实例化类为对象。
类中的成员变量会被初始化为默认值。具体默认值参考:
1 | //默认值: |
new出来的对象在堆中,直到被垃圾回收。而执行方法的语句和这个方法的局部变量在栈中,当执行这个语句时会把变量压入栈,一旦方法执行完毕,方法中的数据会被立马弹出栈。
Java常用类
字符串类
String
最常用的字符串,底层是用final修饰的数组,所以值不可改变。
可以利用”+”号连接字符串,但不能直接用于数值计算。值得注意的是:
当利用String str = "abc";定义一个String对象时,”abc”这个字符串会被放入字符串常量池,其他的字符串对象会共用这个”abc”字符串内容。
而利用String str = new String("abc");定义时,这个str指向堆中的对象。
我们知道,”==”对于基本数据类型是比较数值,而对于引用类型是比较地址值,显然,第二种方式创建的对象在堆中的地址是不同的,所以会返回false,而常量池中的对象地址相同,会返回true
高频常用方法:
1. equals():由于String类重写了Object类的equals()方法返回一个boolean值,建议在比较字符串时使用equals()方法而不是”==”
2. compareTo():由于String类实现了Comparable接口并重写了compareTo()方法,当两个字符串相同时,会返回0
StringBuilder
可变长度的字符串,初始长度为16加上字符串参数的长度。
例如:StringBuilder s = new StringBuilder("123");的长度为16+3=>19
不能使用”+”号连接,可利用append()方法追加StringBuilder对象。
可以使用toString()方法返回此StringBuilder对象的String类形式。
StringBuffer
相当于线程安全的StringBuilder,由于做了同步操作,速度略慢于StringBuilder
日期类
Date类
Java中时间的计算以1970年1月1日00:00:00为起点,计算至今的毫秒值。
创建一个当前系统时间的Date对象的方法:Date date = new Date();
Date类常用方法:
1. getTime():返回Date类对象的毫秒值
2. setTime():参数传入一个long类型的毫秒值,以设置Date对象的日期
3. getYear():返回Date对象的年份
4. getMonth():返回Date对象的月份(注意:此月份比实际月份少1,因为范围为0-11)
5. getDate():返回Date对象在月份中的天数
6. getDay():返回Date对象在一周中的星期几(注意:星期日为0)
Calendar类
Date类中的大部分方法已经由Calendar类代替。
注意创建Calendar对象的方法:Calendar cal = Calendar.getInstance();
创建的Calendar对象包含很多字段(Field),例如一年中的第几天、一年中的第几周、年份、月份、天数等等…
Calender类常用方法类似于Date类,获取字段的方法集中在get()方法中:
1. getTime():返回Calendar类对象的毫秒值
2. get():参数可以为YEAR、MONTH、DAY_OF_YEAR等等…
同样的,注意Date类和Calendar类的月份都比实际月份少1,因为范围为0-11
集合类
List<E>接口的集合
List<E>接口的集合类似于数组,它有3个特点:
1. 有序的
2. 有索引
3. 允许存储重复元素
ArrayList<E>
底层是数组,查询快,增删慢
LinkedList<E>
底层是双向链表,查询慢、增删快(区别于Vector,LinkedList不同步)
有特有方法:
1. addFirst(E e):插入e到开头
2. addLast(E e):插入e到结尾
3. getFirst(E e):返回第一个元素
4. getLast(E e):返回最后一个元素
Vector<E>
底层是数组,查询快,增删慢(区别于LinkedList,Vector是同步的)
特有方法:addElement(E e):将e添加到此集合末尾,并使大小+1
Set<E>接口的集合
Set<E>接口的集合重要特点是不允许重复元素,特点为:
1. 不包含重复元素
2. 无索引(所以也就不能用普通for循环遍历,可以使用迭代器或增强for循环)
HashSet<E>
特点:
1. 底层是哈希表,查询速度极快
2. 无序的
LinkedHashSet<E>
1. 底层是哈希表,查询速度极快
2. 有序的(多了一个链表记录顺序)
Map<K,V>接口的集合
Map集合是一个双列集合,由键K和值V组成,其中键K不允许重复
特点:
1. K不能重复
2. K和V的类型任意
3. 每一个K只对应一个V
常用方法:
1. put(K k,V v):把一个元素放入集合,如果K已经存在则替换原来的V为新V
2. get(Object k):取出K对应的V,如果不存在则返回null
3. remove(Object k):删除K指定的键值对
4. clear():清空这个Map集合
Swing图形化
Java的图形化
我们主要学习Swing和AWT,但是AWT是早期SUN公司提供的GUI开发工具包,它与Swing最显著的特点就是AWT是利用了操作系统提供的图形库,其缺点很明显:显然每个操作系统的图形库是不同的,这导致AWT的跨平台GUI软件界面不统一。
而Swing是Java基础类的一部分,它提供了比AWT更好的显示元素,而且是用纯Java写的,但显然,运行速度肯定是直接调用操作系统图形库的AWT更快,所以AWT叫做重量级组件,而Swing叫做轻量级组件(不用怀疑,没有写反)。
我们可以简单的判断一个组件是否是Swing组件:Swing组件以’J’开头,例如JLabel、JButton。
Swing组件和容器
组件不能单独启动,要放在容器中。
容器(Container)也是组件(Component)的一种。
我们最常用的JFrame容器就是Container的一个子类,显然,也是Component的一个子类,见下方继承图。
其他诸如JLabel就是JComponent的一个子类,这里的JComponent其实也是Container的一个子类,当然,也就是Component的一个子类了(子类什么的看下方继承图!)。区别就在于’J’开头的组件存在于javax.swing包下,而普通组件在java.awt包下。
来看看我们最常用的独立容器:JFrame的继承图:
显然,JFrame继承自Frame,同样的,也继承自更高层的父类Window、Container以至于Component,别忘了,Java中最最高级的根父类是Object,那么它也间接继承自Object类,并实现了一些接口罢了。
看看容器有哪些:
常用Swing组件
JFrame
用于创建一个窗口
首先导入包:
1. import javax.swing.;
2. import java.awt.;
构造方法:
Frame fm = new Frame()创建一个不可见的窗口
Frame fm = new Frame(String title)创建一个带标题的不可见的窗口
发现了吗?创建的窗口都不可见,因为创建的窗口默认高度宽度都为0,而且可见性为false。那么想要显示窗口,就需要两步:
1. setSize(int width,int height) :设置一个宽度和高度
2. setVisible(boolean b) :设置可见性为true
值得注意的是JFrame的默认布局为BorderLayout,这可以使你轻松创建一个具有上、下、左、右、中,一共5个区域的布局,但在BorderLayout中,方向以东南西北中表示。
JPanel
是一个中间容器,必须放置在其他容器中,采用了双缓冲,减少窗口闪烁。
经常用于把其他组件加入到JPanel中,再把JPanel一次性加入到其他容器中。
JLabel
用于显示文本或图片。默认文本靠左对齐,上下居中对齐。
常用方法:setText(String text)设置这个JLabel的文本
JTextArea
一个用来显示文本的多行区域。
使用技巧:如果想要这个多行文本区域具有滚动条,可以把这个JTextArea加入到JScrollPane组件中。
JButton
一个按钮,可以实现ActionListener动作监听器来响应点击事件。这个点击事件的处理在actionPerformed()方法中。
你需要把这个按钮调用addActionListener(ActionLisenter l)并传入一个动作监听器,当你在本类实现了ActionLisenter接口中的方法,那么可以直接传入this
JComboBox
一个下拉列表,可以设置单选、多选等模式。
常用方法:
1. getSelectedIndex():获取当前选择项的索引
2. getSelectedItem():获取当前选择项(Object类型)
3. addItem(E item):把一个泛型元素加入到下拉列表
4. removeItemAt(int index):删除指定索引的元素
3. removeAllItems():删除列表所有的元素
常用布局
设置布局调用setLayout()方法传入一个实现了LayoutManager接口的布局对象,例如FlowLayout、GridLayout等…
就像这样:this.setLayout(new FlowLayout);
或者针对某个面板设置它的布局:
1 | JPanel pn = new JPanel(); //创建JPanel对象 |
Swing相比AWT新增了BoxLayout布局,然而我们主要学习以下三种布局:
FlowLayout
流式布局,元素按照从左到右依次排列,元素大小不变,位置会变,默认水平垂直间距均为5
GridLayout
网格布局,构造方法中指定一个行数和列数,元素大小会变,相对位置不变,默认为1行0列,水平垂直间距均为0;
BorderLayout
边框布局,构造方法中指定水平间距和垂直间距,CENTER部分大小会变,四周大小不变,默认水平垂直间距均为0;
在上面的GUI软件中,很明显主体采用BorderLayout,这种边框布局在放入组件时需要指定放入到东南西北中的哪个位置,否则默认为CENTER,中间的留言内容区域为CENTER区域,而下方的表情选择、输入框都在SOUTH区域,右侧的6个按钮在EAST区域,还有”留言板”的小标题在NORTH区域,WEST区域没放东西。
而SOUTH区域明显有JLabel标签、JComboBox下拉列表、以及JTextField单行输入框和一个JButton提交按钮,这些组件都是从左到右依次排列的,那么就很显然是FlowLayout流式布局了。
右侧EAST区域的6个按钮排列整齐,可以利用一个8行,但只有1列的GridLayout网格布局放置这些按钮。
顶部NORTH区域就不用说了,只有一个组件,随便什么布局都可以,但也建议使用FlowLayout流式布局。
保姆级案例
创建一个窗口
就像在1.5.2中说的那样,创建一个窗口要导入包、设定构造方法、设置大小和可见性。具体来说就是首先继承JFrame类,然后定义构造方法…
1 | import javax.swing.*; |
往窗体里添加一些东西
我们添加了一个文本标签JLabel到JFrame中一共花了4步,而且由于JFrame默认是BorderLayout布局,所以在第4步调用add()方法时,可以指定添加到东南西北中哪个方位,这里我们就加入到了南方(也就是下方)。
显然,我们如果想再加入一个文本在最上方(也就是NORTH北方),就像这样:
发现什么区别了吗,我们这次只花了2步,相对于上次并没有new什么JPanel,而是直接把new出来的JLabel文本标签直接add到NORTH北方区域,文本靠左对齐了,就像在1.5.3.3中讲的那样(你不会才知道右侧有目录吧?!),其实就是这两步:
但是上面的JLabel文本标签没有居中对齐,逼死强迫症?只需要调用setHorizontalAlignment()方法传入一个int数值就可以,居中CENTER其实相当于写0:
现在假设我们需要一个文本区域,可以供我们输入很多文字,而且这个文本区域最好在窗口中间…那么很明显定义一个JTextArea,然后放入JFrame的CENTER区域就行了:
结合上面几个案例,不难看出,一般情况下添加一个组件到JFrame窗口,两步就够了:
1. new一个你想要的组件,比如JLabel、JTextArea等等
2. 调用add()方法并指定添加到东南西北中哪个方位
关闭按钮
然而实际上自己运行一下会发现,我们做的窗口点击关闭按钮后,窗口确实消失了,但是你的IDE(比如eclipse、IDEA)并没有显示这个进程退出了,也就是说你的窗口程序还在运行。
所以想让窗口的关闭按钮正确结束掉你的窗口程序,常用的有以下两种方法:
1. 调用addWindowListener()传入一个WindowAdapter对象并重写windowClosing()方法,方法内执行System.exit(0);
2. 调用setDefaultCloseOperation()并传入一个int值,例如3相当于EXIT_ON_CLOSE
反正我是喜欢第二种关闭方法,一句话搞定。
JPanel(面板)的作用
通过以上案例,你已经能写出一个可以随心所欲设置放置到哪个位置的窗口程序,并且关闭按钮也可以正常结束掉程序。但是有没有注意到,我们第一次添加那个JLabel文本标签的时候,它是被放入到一个JPanel面板中的,而且它竟然居中了,这是由于JPanel默认为FlowLayout流式布局,会从左到右依次排列组件并且居中。
也就是说,我们可以把一些乱七八糟的组件都加入到一个JPanel面板中,最后一次性把JPanel加入到JFrame的某个位置就行了。
运用同样的方法,你可以把一些乱七八糟的组件都加到另一个面板中,然后一次性把面板加入到其他位置,比如SOUTH南方放置上面案例中的那些组件,而EAST东方可以放置一些按钮,这些按钮都放在一个面板中,NORTH北方也可以放一个面板,面板里面可以放置一下乱七八糟的组件…