前言
类和对象
如何创建自己的类
成员变量与成员函数package、importStatic—类对象/函数(静态) 继承(extends)
super多态Object类 泛型(generic)抽象(abstract)
重写(Override)& 重载(Overload)
@Override@Overload Java集合框架
ArrayListHashSetHashMap 一些你必须了解的小知识点
Stack数据结构StringBuffer类Iterator(迭代器)Java正则表达式 Java异常处理
throws 与 throw 的区别
捕获异常 使用IDEA的一些小技巧
Junit测试方法 结束语
前言类和对象 一共会出三篇关于Java的学习笔记, 分别为:
【基础语法篇】【面向对象篇】【高级教程篇】
大家可以在日常的学习生活中进行参考,笔记内容并不是绝对权威,所以请保持自己独立思考的能力。
⭐码字不易,求个关注⭐
⭐点个收藏不迷路哦~⭐
面向对象程序设计(OOP)
想要理解OOP,必须先理解类和对象。
类 是构造对象的模板,作为对象的规范而存在。
其中有成员变量和成员函数,可以认为成员函数中包括构造函数,而通过构造函数可以构造一个对象。
构造函数应与类名相同,所以我们会看到这样的一幕:Scanner ()就是一个构造函数。
Scanner in = new Scanner (System.in);
这同时也为我们引出了对象······我们使用 new+构造函数 创建对象。其中in是对象变量,但对象变量是对象的管理者,并非对象本身。
如何创建自己的类补充:关于对象的定义,在《Java核心卷》中提到:定义对象应先了解对象的三个特征。
1. 对象的行为-通过方法定义
2. 对象的状态-状态的改变通过调用方法实现
3. 对象的标识-作为类的实例,每个对象的标识都不同
例如:我们熟悉的in.nextInt(); 就是对象变量调用了Sanner类的方法nextInt。这就定义了对象的行为,可以让对象为我们做事。
上文提到了方法一词,其实方法就是类中的成员函数。想要创建自己的类,首先应该明白以下三条书写规则。
- 成员变量:private +变量类型+变量名称构造函数:public +类名 () {}成员函数:public +函数类型 +函数名称() {}
大家可能会注意到前面的public/private,这是Java访问修饰符。顺便通过这个来介绍封装。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问,一般使用private即可实现这种功能。
public:
使变量/函数在任何地方都可以被访问。private:
只能用于成员变量和成员函数。
使成员变量/函数只有在类里可以访问。(在同一个类的不同对象之间也可以相互访问。)
不加public(friendly):
同一个包内可以访问。protect:
子类和父类在同一个包内可以访问。
成员变量与成员函数还要明确以下几点规则:
在一个源文件(.java)中,只能有一个公有(public)类,但可以有无数个非公有类。public类名要与源文件名相同,构造函数要与类名相同。程序中会存在默认构造器。
上文提到了类由成员变量和成员函数组成。
类定义了对象中所具有的变量,这些变量称为成员变量。每一个对象都有自己的变量,和同一类的其他对象是分开的。所以成员变量的生存期是对象的生存期,作用域是类内部的成员函数。
Java是用文件夹去管理包的。包的名字可以加 . 表明文件夹的层次。
import
语句:import 包.类
import 可以提供一个路径,使得编译器可以找到某个类。
比如在使用Scanner类之前通常会有一句import java.util.Scanner;
如果不用import,就需要写出类的全名:(包.类)
Static—类对象/函数(静态)
具有static修饰符的变量叫做类变量(静态变量)。
表明变量不在任何对象中,而是在类中,且只有一个。
举例:
如果将域定义为 static, 每个类中只有一个这样的域。而每一个对象对于所有的实例域
却都有自己的一份拷贝。具有static修饰符的函数叫做类函数。
表明函数不属于任何对象,而是属于这个类。,static函数和static函数之间可以访问。static函数的调用:
静态(static)方法可以不用创建对象就调用,非静态方法必须有了对象的实例才能调用。
注:在调用时,通过类调用或通过对象调用都是相同的,但更推荐通过类调用类函数/类变量。(这时以下两种语法将表达同一种意思:(类.具有static的方法/变量)==(对象.具有static的方法/变量)。)
继承(extends)
众所周知,面向对象程序设计语言有三大特性:封装、继承和多态性。前面已经介绍过封装,接下来我们来介绍继承。
什么是继承?
继承表示父类与子类之间的关系,子类通过继承父类所有非私有的方法,从而达到重复使用父类数据和方法的效果。为什么要用继承?
降低代码的复用性。怎样用继承?
public class Thisclass extends Superclass{
//表示Thiscalss派生于Superclass
}
参考代码:
Java的继承代码演示
super有两个用途,一个是调用父类的构造器,一个是调用父类的方法。
作为前者:
当父类的构造器无传参时,构造子类对象会先进行父类的定义初始化和调用构造器。
如果子类和父类中有同名的成员变量,子类就是子类自己的,父类中的会被隐藏。
代码示例:
class Supclass{
int x=2;
SuperClass(int x){
this.x=x;
}
}
class SubClass extends SuperClass{
int x1=1;
SubClass(int x,int x1){
super(x); //必须放在构造函数的第一句话。
this.x1=x1;
}
}
作为后者:
若子类和父类中有同名的函数,可以使用super和.调用父类的函数。
实现多态的前提:继承+重写。
子类的每个对象也是超类的对象。比如:用来放父类对象的容器也可以用来放子类的对象。Java的对象变量是多态的,能保存不止一种类型的对象。
造型(cast)
子类的对象赋给父类的对象变量——向上造型。可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
public class TestDemo {
public static void main(String[] args) {
Animal a2 = new Cat();//向上造型
// 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型
// 必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/
a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体
}
}
class Animal{
//3.创建父类的普通方法
public void eat(){
System.out.println("小动物Animal吃啥都行~");
}
}
//子类和父类中存在名称和参数完全相同的函数,这一对函数构成覆盖关系。
//通过父类的变量调用时,会调用变量当时管理的对象所属类的函数。
class Cat extends Animal{
//4.1添加重写的方法
public void eat(){
System.out.println("小猫爱吃小鱼干~");
}
}
}
————————————————
参考原文代码链接:https://blog.csdn.net/weixin_43884234/article/details/116593803
绑定
当通过变量对象调用函数,调用哪个函数叫做绑定。
- 静态绑定:变量实际的类型。动态绑定:根据变量的动态类型来决定。
Java中所有的类都是从Object继承的,所以有必要简单了解以下Object类。
Java Object 类是所有类的父类,Object 类可以显示继承,也可以隐式继承。
有时常用Object类中的方法或重写方法。例如toString方法,用来显示对象的字符串形式。还有equal()方法等······
泛型是什么?
元素类型不确定,所以设计一个参数,这个参数叫做泛型。
例如ArrayList< E>,< E>就是泛型。
总之,就是通过一个标识,影响方法的参数类型。使用泛型的作用?
1.编译时会进行类型检查,保证数据的安全。
2.避免了类型转换异常出现的情况。使用泛型的注意?
1.使用泛型,不可以用基本数据类型,必须用其包装类。
2.Java集合接口和集合类jdk1.5之后都被修改为带泛型的结构。
抽象(abstract)
抽象:父类只是定义了一个抽象函数的概念,而具体的方法要交给子类实现。
抽象函数:表达某一个概念,无法具体实现代码的一种函数。
如果一个方法是抽象的,那么它的类也应该是抽象的。
如果父类是抽象的,子类必须涵盖父类所有抽象的方法,(实现父类的抽象的方法)或子类也变为抽象类。
设计这样的类是为了防止抽象类生成对象。
子类能够根据需要实现父类的方法。
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!super关键字
当需要在子类中调用父类的被重写方法时,要使用 super 关键字。
@Overload
- 方法重载是一个类中定义了多个方法名相同,而他们的参数数量不同或参数类型和次序不同,则称为方法的重载(Overloading)。方法重载(Overload)是一个类的多态性表现,而方法重写(Override)是子类与父类的一种多态性表现。
由于涉及集合过多,这里只是简单介绍一些常用的集合框架,掌握通用的思想即可。
链接:菜鸟教程—Java集合框架
Java 集合框架主要包括两种类型的容器:
一种是集合(Collection),存储一个元素集合。
一种是图(Map),存储键/值对映射。
集合框架主要包括三个内容
接口:代表集合的抽象数据类型。(Collection、Map、List、Set)实现(类):具体对于某种集合的实现,比如:ArrayList、HashMap、stack、linkedList。算法:具体类的方法的实现。
通用语句:ArrayList
(E:泛型数据类型,设置objectName的引用数据类型,要用基本类型的包装类型。
ArrayList:容器的类型。)
特性:可动态修改的无限数组。
(API)
// 增: notes.add(String); //往容器内加入东西。 notes.add(String,index)//把String插入到index的位置。后面的东西自动向后顺位。 String a=new String [notes.size()]; notes.toArray(a); //将String 类型的数组 a 放入容器中。 //删: notes.remove(index); //删除index位置的东西。后面的东西自动向前补位。 //改: notes.set(index,String); //修改第index位为String。 //查: notes.get(index); //得到容器内的第几位。(从一开始计数) notes.size(); //得到容器大小。
HashSet关于对象数组的小细节:
int类型的数组(基础类型的数组):放着每一个int。
String类型的数组(对象数组):放着每一个String的管理者。
for-each 循环:对于对象数组,可以修改所管理的对象。
特性:在HashSet内没有重复的东西,不排序,类似一个集合。(线程不安全)
(API与AttayList类似)
Map接口
Map 接口存储一组键值对象,提供key(键)到value(值)的映射。HashMap
HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
HashMap 是无序的,即不会记录插入的顺序。
特性:同一个key放入多次,只留下最后一次。(一一对应)
(API)
HashMap coinnames = new HashMap(); coninames.put(key,value); //放进容器。 coinnames.get(key); //得到key对应的value。 coinnames.containsKey(key); //如果存在key的话,返回true。 coinnames.keySet(); //返回key的集合。 coinnames.keySet().size(); //返回key的集合的个数。 //遍历HashMap(): for(Integer k : coinnames.keySet()){ String s = coinnames.get(k); System.out.println(s); }
一些你必须了解的小知识点 Stack数据结构ArrayList,HashSet,HashMap都可以用sout进行输出。(当里面放的是包裹类型时可以,但如果是对象变量,只会输出地址,因为对象变量是对象的管理者)
当语句:System.out.println(s);执行时,会主动调用类中public类型的成员函数并且返回String的函数。类似:(public String toString (){})
stack可以实现先进后出。
Stack
| 描述 | 方法 |
|---|---|
| 入栈 | stack.push() |
| 出栈 | stack.pop() |
| 判断是否为空 | stack.empty() |
| 查看栈顶 | stack.peek() |
| 返回在栈中的位置(1为基数) | stack.search() |
public class Test{
public static void main(String args[]){
//创建StringBuffer对象sBuffer。
StringBuffer sBuffer = new StringBuffer();
//将指定的字符串追加到此字符序列。
sBuffer.append("1");
sBuffer.append("2");
sBuffer.append("3");
System.out.println(sBuffer);
}
}
使用StringBuffer类对字符串进行修改,这样不会每一次修改就产生一个新的对象,减小系统的开销。
StringBuffer中为了适应字符串内容的改变,拥有一块内存缓冲区,缓冲区的长度为StringBuffer的容量,而字符串长度指包含的实际字符的个数。
参考链接:菜鸟教程—StringBuffer类
Iterator不是一个集合,而是访问集合的方法,可用于迭代ArrayList和HashSet等集合。
public class Demo {
ArrayList list=new ArrayList<>();
public static void main(String[] args) {
Demo demo=new Demo();
demo.add(1); demo.add(2); demo.add(3);
//迭代器的创建,这里引用了iterator方法。
Iterator it=demo.list.iterator();
//一般使用while语句来进行遍历。
while(it.hasNext()){ //用来判断迭代器是否还有元素。
if(it.next()<2) { //返回当前所指元素。
it.remove(); //删除当前所指元素。
}
}
System.out.println(demo.list); }
public void add(int a){ list.add(a); }
}
Java正则表达式
正则表达式可以用来搜索、编辑或处理文本,一个字符串就是一个简单的正则表达式,例如:
Hello World 正则表达式匹配 “Hello World” 字符串。
d:匹配数字字符,+:等效于{1,}
还有很多,这里就不一一列举了。
Matcher类(支持正则表达式)的方法:包括索引、查找、替换的方法,如果需要的同学可以自查:菜鸟教程—Java正则表达式
Java异常处理
Java提供了异常处理机制,并且定义了很多异常类,每个异常类都代表一种类型的异常,
如果方法运行产生了异常,该方法就会生成异常对象,并交给专门的异常处理代码对异常对象进行处理。
Java异常处理的作用:
Java的异常处理机制将异常处理代码和程序功能实现代码分开,程序员不必花大量精力去编写代码来测试方法的返回值及错误的检测,使得错误代码更有条理性,更便于维护。
throws
用在方法声明处,其后跟着的是异常类的名字。
表示此方法会抛出异常,需要由本方法的调用者来处理这些异常。
但异常不一定会发生。throw
用在方法的内部,其后跟着的是异常对象的名字
表示此处抛出异常,由方法体内的语句处理
注意:执行throw一定抛出了某种异常
捕获异常
使用以下代码即可捕获保护代码块中的异常
try{
//保护代码块
}catch(Exception e){
//catch块
}
多重捕获块
try{
//程序代码
}catch(异常类型1 异常的变量名1){
//程序代码
}catch(异常类型2 异常的变量名2){
//程序代码
}
如果保护代码中发生异常,异常被抛给第一个 catch 块。
如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。如果不匹配,它会被传递给第二个 catch 块。
如此,直到异常被捕获或者通过所有的 catch 块。
菜鸟教程—Java异常处理
JUnit是单元测试的基础单元测试框架。每编写完一个函数之后,都应该对这个函数的方方面面进行测试。 在每个方法前加入@Test,alt+enter即可导入JUnit4进行单元测试。
结束语关于【基础语法篇】大家可以看之前写的文章,作者也是一边学习一边写作,如有错误也请大家指出,我们一起交流讨论学习。
最后,如果这篇文章对你有帮助的话,不妨点个收藏再走哦!



