本篇是关于Java的杂记,部分转载与其他博客,用于索引使用。
方法返回值
方法返回值使用方法与c语言类似,返回基本数据类型或void
package Test;
public class Test {
public static void main(String[] args) {
System.out.println(int_back());
}
static int int_back() {
return 1;
}
static void void_back() {
// nothing
}
}
除此之外,你还可以返回一个对象地址
static Test new_Test() {
return new Test();
}
还可以返回泛型类型,放到后续章节里吧
继承
什么是继承?
继承提供了一种方式,使得你可以通过已有的类创建新类,这个新类是旧类的特殊版本,它有着和旧类一样的方法,属性。
术语
超类(父类):这个类允许在其他类里重用他的成员
派生类(子类):继承父类的类(我知道是废话,其实父类那个也是)
代码实现
让我们先看看完成一个继承需要的必要符号 :extends
class Student{
public String name;
public int age;
}
class Undergrad extends Student{
public Undergrad(){
this.name="CZT";
this.age=20;
}
}
你可以通过“就是”这个词来理解继承,比如本科生和学生的关系:本科生就是学生,这样本科生就是子类,学生就是父类,本科生有着学生的特点。
一个子类里拥有什么?
- 所有子类里定义的成员
- 所有父类里声明的成员
一个子类能使用什么?
- 所有子类里定义的成员
- 所有父类里定义的成员
注意:一些类不能够被继承,比如以final关键字定义的类
还有一件重要的事,一个子类只能继承一个父类!
类访问权限符
public
: 子类的对象可以视为父类的对象protected
:比public有更严格的限制, 但允许子类知道父类的详细信息。private
: 防止将子类的对象视为父类对象
super与this关键字
- super允许子类调用父类的成员
- this调用本类的成员
class Student {
public String name;
public int age;
public void setAge(int a) {
age = a;
}
}
class UnderGrad extends Student {
public UnderGrad() {
this.age = 10;
this.name = "John Doe";
}
public void set_age(int a) {
if (a < 50) {
age = 0;
} else {
super.setAge(a);
}
}
}
class example {
public static void main(String[] args) {
UnderGrad one = new UnderGrad();
System.out.println("子类构造方法初始化了age: " + one.age);
one.set_age(50);
System.out.println("Age after set_age(50) is called: " + one.age);
one.set_age(10);
System.out.println("Age after set_age(10) is called: " + one.age);
}
}
结果:
子类构造方法初始化了age: 10
Age after set_age(50) is called: 50
Age after set_age(10) is called: 0
重载
方法名相同,参数类型或数目不同
public class Test {
public static void main(String[] args) {
A(1);
A(1,2);
}
static void A(int a) {
System.out.println(a);
}
static void A(int a,int b) {
System.out.println(a+b);
}
}
根据参数的数目,匹配应调用哪个方法
成员变量和局部变量总结,Java构造方法总结。
在Java语言里,根据定义变量位置的不同,可以将变量分成两大类:成员变量(存在于堆内存中,和类一起创建)和局部变量(存在于栈内存中,当方法执行完成,让出内存,让其他方法来使用内存)。二者的运行机制存在较大差异。
成员变量
成员变量存在于类中,当类被实例化时,成员变量就被创建,占用堆空间,并在栈中指向堆空间。当没有栈中的地址指向此空间时,该实例就被回收。
局部变量
局部变量根据定义形式的不同,又可以分为如下三种:
形参:在定义方法签名时定义的变量,形参的作用域在整个方法中都有效
方法局部变量:在方法体内定义的局部变量,它的作用域是从定义该变量的地方生效,到该方法结束时失效
代码块局部变量:这个局部变量的作用域从定义该变量的地方生效,到该代码结束时失效。
一个变量只在一对{}中起作用。
java允许局部变量和成员变量同名,如果方法中局部变量和成员变量同名,局部变量就会覆盖成员变量,如果需要在这个方法中引用被覆盖成员变量,则可使用this(对于实例变量)或类名(对于类变量)作为调用者来限定访问成员变量。
构造方法
构造方法作用就是对类进行初始化。 如果你没有定议任何构造方法的形式,程式会为你取一个不带任何参数的构造函数,那么你产生类的对像时只能用不带参数的方法。
构造方法就是与类同名的那个方法,它的作用是可以用来初始化,例子如下
class Person //人类{
public Person(String n,int a) //构造方法
{
name = n; age = a;
}
private string name;
private int age;
}
static void main(String[] args){
Person p = new Person("张三",14);//这就是作用
}
new一个对象的时候要用到构造函数,例如Hello hello = new Hello();这时调用的是Hello的无参数构造方法。
Hello hello = new Hello(“hi”);这个是调用Hello有参数构造方法,在JAVA中如果不写构造方法的话,会默认加上一个无参数的构造方法,但是如果已经有了一个有参数的构造方法,那么无参数的构造方法就不会默认被加上。
如果Hello类中已经有了一个有参数的构造方法,这时再使用 Hello hello = new Hello();来创建对象的时候就会出错,这就是为什么书上要强调写了有参数的构造方法就最好加一个无参数的构造方法。
抽象类和接口的区别
- 抽象类通过 abstract 关键字来定义,然后子类通过 extends 继承该抽象类后并实现相应抽象方法;接口通过 interface 关键字来定义,子类通过 implements 来实现该接口中的所有方法。
- 抽象类中的抽象方法可以使用 public、protected、default 修饰符;接口中的抽象方法默认并只能是 public,并且成员变量默认为 public static final 修饰的,所以我们可以直接通过 接口名.成员变量 使用它。
- 抽象类中允许有非抽象的方法和成员变量包括构造方法; 接口中的方法全是抽象的,不能有方法的实现。
- 子类只能通过继承来实现抽象类,由于 java 中的单继承特性,就导致只能继承一个抽象类;但是子类可以实现一个或多个接口,在一定程度上,这就解决了由于单继承特性所带来的问题。
- 从作用上来看,抽象类是为了把相同的东西提取出来,即重用;接口是为了把程序进行模块化,可以降低程序的耦合。
匿名内部类
匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下:
new 父类构造器(实参列表) | 实现接口()
{
//匿名内部类的类体部分
}
从上面的定义可以看出,匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。
两条规则。
匿名内部类不能是抽象类。
匿名内部类不能定义构造器。由于匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以初始化块,可以通过初始化块来完成构造器需要完成的工作。
package Test;
abstract class cat{
void say(){};
}
public class Test{
public static void main(String arg[]) {
cat A=new cat() {
void say(){
System.out.println("叫了一声");
};
};
A.say();
}
}
检查时异常与运行时异常
通常,Java的异常(包括Exception和Error)分为
检查异常(checked exceptions)和非检查的异常(unchecked exceptions)。
其中根据Exception异常进行划分,可分为运行时异常和非运行时异常。
What:什么是检查异常(checked exception)?
就是编译器要求你必须处置的异常。编译器要求你必须要对这段代码try…catch,或者throws exception,如果遇见过,就是检查异常,也就是说,你代码还没运行呢,编译器就会检查你的代码,会不会出现异常,要求你对可能出现的异常必须做出相应的处理。
How:怎样处理检查异常(checked exception)?
1、继续抛出,消极的方法,一直可以抛到java虚拟机来处理,就是通过throws exception抛出。
2、用try…catch捕获
注意,对于检查的异常必须处理,或者必须捕获或者必须抛出
Where:检查异常有哪些呢?
除了RuntimeException与其子类,以及错误(Error),其他的都是检查异常。
集合与泛型
ArrayList和vector均为java.util包中的类,相当于可变长数组。
- ArrayList适合单线程,非线程同步
- vector适合多线程,线程同步
使用ArrayList和vector和c++中类似,功能也相似,但java中的集合也可以存放不同元素类型的元素,因为他们都属于Object类。
package Test;
import java.util.ArrayList;
public class Test{
public static void main(String[] args) {
ArrayList <Object> list=new ArrayList<Object>();
list.add("陈");
list.add(12);
System.out.println(list); //输出整个集合元素
//输出:[陈, 12]
}
}
我们也可以自定义泛型类
package Test;
class Student<T>{
private T things;
public T getThings() {
return things;
}
public void setThings(T things) {
this.things = things;
}
}
public class Test{
public static void main(String[] args) {
Student <Integer> stu1 =new Student<>();
stu1.setThings(10);
System.out.println(stu1.getThings());
Student <String> stu2 =new Student<>();
stu2.setThings("车票");
System.out.println(stu2.getThings());
}
}
//输出
10
车票
集合根接口为Collection<E>,所有集合类都实现了根接口,下面的方法在子接口List,Set,Queue中均可使用
Colloction除了有子接口,还有父接口Iterable<E>,接口有一个方法iterator(),返回方法为Iterator<E> //说了这么绕,其实和c++差不多的语法。
Iterator<E>有3个主要方法
- hasNext() 判断是否有元素
- next() 返回下一元素
- remove()移除元素
下面给出了三种遍历的方式
package Test;
import java.util.Iterator;
import java.util.Vector;
public class Test{
public static void main(String[] args) {
Vector<Integer> vec=new Vector<>();
vec.add(1);
vec.add(3);
vec.add(5);
Iterator<Integer> it=vec.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
for(Integer out:vec) {
System.out.println(out);
}
vec.forEach((e)->System.out.println(e)); //Lambda遍历
}
}
无重复元素接口Set<E>
Set中没有重复的元素,使用方式和Collection<E>相同,实现Set<E>的接口有两个
- HashSet<E> 按照哈希法进行排序
- TreeSet<E> 按照元素自然顺序从小到大(或自行设定的顺序)排序
比如重复添加了两个3,输出仅为1个
package Test;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
public class Test{
public static void main(String[] args) {
Set<Integer> vec=new HashSet<>();
vec.add(1);
vec.add(3);
vec.add(3);
Iterator<Integer> it=vec.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
for(Integer out:vec) {
System.out.println(out);
}
vec.forEach((e)->System.out.println(e)); //Lambda遍历
}
}
输出
1
3
1
3
1
3
数据封装类与自动装箱拆箱
调用封装类构造方法,能把基本数据封装成对象。
Integer obj =new Integer(8);
这种把基本类型数据封装成对象的方法,叫装箱。
把对象内部基本数据提取出来,称为拆箱。
Boolean obj =new Boolean(true);//装箱
boolean b=obj.booleanValue();//拆箱
自动装箱与自动拆箱
JDK1.5开始,允许把基本数据类型直接赋值给对应的封装类型
Integer obj =new Integer(10); //装箱
int i=obj; //自动拆箱
int sum=obj+obj;
Integer obj2=obj+obj;//自动拆箱后再装箱
映射接口MAP<K,V>
K是健,K不允许重复,相当于函数的自变量。
V是值,V可以重复,相当于函数的因变量。
HashMap<K,V>与哈希表HashTable<K,V>
这两个功能大致相同
- HashMap<K,V> 线程非同步,健和值允许null
- HashTable<K,V> 线程同步,键和值不允许null
HashMap有四个构造方法(从书上运下来,括号里省略了变量名)
加载因子0.75表示,使用了75%的容量后,自动增加约2倍的量
HashMap() | 构造一个初始容量16,加载因子0.75的空映射 |
HashMap(int ) | 指定初始容量,加载因子0.75 |
HashMap(int,int) | 指定初始容量和加载因子 |
HashMap(Map<K,V> ) | 构造一个与给定映射相同的新映像 |
HashTable也有这四个构造方法,不过初始容量是11。
package Test;
import java.util.HashMap;
import java.util.Map;
public class Test{
public static void main(String[] args) {
Map<String,String> map=new HashMap<>();
map.put("学号", "12346");
map.put("年龄","13");
map.put("籍贯","黑龙江");
map.remove("籍贯");
System.out.println(map);
}
}