标签:Java String int void 接口 基础知识 out public 入门
本文内容来自本人在学习Java过程中整理的笔记,供自己日后翻阅,也可以作为Java入门基础的读者一部分学习资料,有问题欢迎留言,知无不言。
1.当一个类有多个构造器时,一个构造器调用另外一个构造器,可以使用this。
- class Post {
- private String title;
- private String content;
- public Post(String title) // 第一个构造器
- {
- this.title = title;
- }
- public Post(String title, String content)// 第二个构造器
- {
- this(title);
- this.content = content;
- }
- }
在第二个构造器中,this(title);这一行代码表示调用第一个构造器。 在构造器比较复杂时,这种方式可以让代码更加简洁。
2.我们也可以定义有参数的构造器,即构造器也是可以重载的。比如:
- class Post {
- private String title;
- private String content;
- public Post(String title, String content)
- {
- this.title = title;
- this.content = content;
- }
- }
这里构造函数具有两个参数。this表示的是当前对象,表示将参数title和content赋给自己对应的成员变量。如果自行定义了构造器,则编译器就不再会为我们生成默认构造器,针对以上Post代码,通过Post post = new Post();来创建Post对象将会产生编译错误。
3.构造器类似于普通方法,但是有两个特殊的地方:方法名称必须和类名相同,不允许定义返回类型。如果你没有定义任何构造器,则编译器会自动帮你生成一个构造器,称之默认构造器。 默认构造器不包含任何参数,会自动调用其父类的无参数构造器。回顾此前Post类的定义:
- class Post {
- private String title;
- private String content;
- }
因为没有显式定义构造器,所以编译器会帮我们生成默认构造器。因此我们可以使用new操作符来调用默认构造器。例如: Post post = new Post();构造器也可以使用public和priavate 修饰。如果使用private修饰,则外部不能通过new操作创建该类的实例。
4.如果一个方法定义了返回类型,在方法体内必须有return语句返回该类型的数据。return后面可以跟字面量、变量或者表达式。return也可以单独使用,不跟任何表达式,表示立即结束当前方法的执行。.return也表示无条件分支,它包含两种用途:(1)return后面跟一个值或者变量,指定一个方法的返回值(2)单独的return;语句,后面不跟任何值或者变量,表示退出当前方法比如我们可以定义一个方法来计算从1到100之和,然后将其返回:
- public static int sumOfNumbers() {
- int sum = 0;
- for(int i = 0; i <= 100; i++)
- {
- sum += i;
- }
- return sum;
- }
5.private:表示任何其他类不能直接访问该成员变量,只有该类自身可以访问
protected:表示只有该类自身及其子类可以访问该成员变量
public:表示任何类都可以直接访问该成员变量。
没有修饰:表示同一个包的类可以访问该成员变量
6.关于类和Java文件的关系:一般情况下,都是一个类一个.java文件如果一个.java文件里有多个类,只可能有一个public的类。而且文件名必须和public类同名如果文件里所有类都不是public的,那么文件名和任意一个类同名即可。
7.continue用于在循环控制结构中,让程序立刻跳转到下一次循环。在for循环中,continue语句使程序立即跳转到控制变量更新语句。在while或者do/while循环中,程序立即跳转到布尔表达式的判断语句。比如,我们计算从1到100的所有偶数之和,我们也可以通过加入continue语句来实现:
- int sum = 0;
- for(int i = 0; i <= 100; i++)
- {
- if (i % 2 == 1)
- {
- continue; // 如果是奇数,则立刻跳转到下一次循环,不做累加
- }
- sum += i;
- }
8.Java利用for语句引入了更为简单的方式来进行Java数据及容器的操作。通过这种方式,我们可以不用引入额外的控制变量。以遍历数组为例: 一般的for循环:
- String[] sentences = {"hello", "thank u", "thank u very much"};
- for (int index = 0; index < sentences.length; index++)
- {
- System.out.println(sentences[index]);
- }
- //可以采用如下方式进行简化:
- String[] sentences = {"hello", "thank u", "thank u very much"};
- for (String sentence : sentences)
- {
- System.out.println(sentence);
- }
9.'=='和'!='作为关系运算符只用来比较对象的引用。如果想比较两个对象实际内容是否相同,需要调用对象的equals()方法。比如判断一个字符串str的内容是否为"abcd",应该这样比较:
- if (str.equals("abcd")) {
- }
- //下面这种方式是一种错误的方式:
- if (str == "abcd") {
- }
10.命名冲突即类同名的情况,想想一下同一个文件夹下是不可以有两个同名的文件的,不同文件夹下就不存在这个问题,包可以看做是存放Java类的不同文件夹。Java平台提供了很多方便我们编程的类,通常称之为类库(lib),也称之为应用编程接口(Application Programming Interface, API)。不仅仅是使用Java平台提供的类需要import,任何一个package中的类,如果需要访问另外一个package中的类,就需要import.
11.引用类型和基本类型的区别
- int color = 0;
- int speed = 100;
- Car myCar = new Car(color, speed);
则内存状态如下:
与引用类型myCar不同,基本类型变量的值就是存储在栈中,作用域结束(比如main方法执行结束)则这些变量占据的栈内存会自动释放。
12.在外部(即其它类中)也可以访问一个类的非private属性,通过对象名.属性名的方式进行访问。例如将Car的color属性设置为public:
- public class Car {
- public int color;
- // ...
- }
如果我们定义一个Driver类,可以这样访问color属性:
- public class Driver {
- public static void main(String[] args) {
- Car car = new Car();
- car.color = 0xffffff; // 修改color属性的值
- int color = car.color; // 访问color属性的值,将其赋给其他变量
- System.out.println(car.color); // 将color作为参数,打印
- }
- }
13.如果自行定义了构造器,则编译器就不再会为我们生成默认构造器,针对以上Post代码,通过Post post = new Post();来创建Post对象将会产生编译错误,除非你显式地增加默认构造器:
- class Post {
- private String title;
- private String content;
- public Post() {
- }
- public Post(String title, String content) {
- this.title = title;
- this.content = content;
- }
- }
14.equals()与==的区别:如果两个字符串变量指向的字符序列内容完全一样,equals()返回true;如果两个字符串变量指向同一个对象,==返回true。
- String str1 = new String("abc");
- String str2 = new String("abc");
- System.out.println(str1 == str2);
- System.out.println(str1.equals(str2));
以上代码,第一个输出为false,第二个输出为true。
15.一个类的成员变量,一个函数中的参数,都具有一种数据类型,可以为基本数据类型(如int类型)或者引用类型(如Car类型)。假设我们想描述平面坐标的一个点,那么我们创建一个Point类,这个类要包含表示X坐标和Y坐标的成员变量:
- public class IntPoint{
- private int x;
- private int y;
- public int getX() {
- return x;
- }
- public void setX(int x) {
- this.x = x;
- }
- public int getY() {
- return y;
- }
- public void setY(int y) {
- this.y = y;
- }
- }
如果我们发现int类型描述平面坐标上的点精度不够,希望换做double类型,那么代码应该大部分是类似的,可是上面的代码我们却无法复用。我们只能再定义一个非常类似的DoublePoint重新定义为:
- public class DoublePoint{
- private double x;
- private double y;
- public double getX() {
- return x;
- }
- public void setX(double x) {
- this.x = x;
- }
- public double getY() {
- return y;
- }
- public void setY(double y) {
- this.y = y;
- }
- }
能否只定义一个类就能满足坐标既可能为int类型,也可能为double类型的情况呢?如果可以的话将可以让代码更加通用,减少大量的重复代码。答案是肯定的,这个时候你需要泛型。
在使用泛型时,我们可以把类型作为参数传入到泛型类中。类似于把参数传入到方法中一样。我们来实现一个通用的泛型Point类
- public class Point<T> {
- private T x;
- private T y;
- public T getX() {
- return x;
- }
- public void setX(T x) {
- this.x = x;
- }
- public T getY() {
- return y;
- }
- public void setY(T y) {
- this.y = y;
- }
- }
此时Point成为了一个泛型类,T是则是类型参数,T具体是什么类型那要看程序运行的时候我们传入什么类型给他。使用泛型类时,注意实际传入的类型参数不能是原生类型,必须是引用类型,因此如果希望传入int类型的话,那么需要传入int对应的包装类Interger。对应地,double类型则要传入包装类Double。
- public class Test{
- public static void main(String[] args){
- // 坐标为int类型,把int类型的包装类Integer作为参数传入泛型类中
- Point<Integer> point1 = new Point<Integer>();
- point1.setX(1);
- point1.setY(1);
- // 坐标为double类型,把double类型的包装类Double作为参数传入泛型类中
- Point<Double> point2 = new Point<Double>();
- point2.setX(3.456);
- point2.setY(4.789);
- }
- }
Point<Integer>等价于IntPoint类,而Point<Double>则等价于DoublePoint类。
再举一个例子,我们定义一个容器类Container,这个容器中可以存放各种类型的对象,可以使用泛型类实现这一特性。
- public class Container<T> {
- private T variable;
- public Container () {
- variable = null;
- }
- public Container (T variable) {
- this.variable = variable;
- }
- public T get() {
- return variable;
- }
- public void set(T variable) {
- this.variable = variable;
- }
- public static void main(String[] args) {
- Container<String> stringContainer = new Container<String>();
- stringContainer.set("this is a string");
- }
- }
我们实例化Container对象时,只需设置它使用的类型,如:
- Container<String> stringContainer = new Container<String>();
- stringContainer.set("this is a string");
16.static的作用:大家都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立。然而在某些时候,我们更希望该类所有的对象共享同一个成员。此时就是 static 大显身手的时候了!Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享。静态成员可以使用类名直接访问,也可以使用对象名进行访问。当然,鉴于他作用的特殊性更推荐用类名访问。使用 static 可以修饰变量、方法和代码块。例如,我们在类中定义了一个 静态变量 hobby ,操作代码如下所示:
- public class HelloWorld {
- static String hobby="kat";
- public static void main(String[] args) {
- System.out.println("通过类名访问hobby:"+HelloWorld.hobby);
- HelloWorld hello=new HelloWorld();
- System.out.println("通过对象名访问hobby:"+hello.hobby);
- hello.hobby="melo";
- System.out.println("再次通过类名访问hobby:"+HelloWorld.hobby);//打印结果:melo
- }
- }
静态成员属于整个类,当系统第一次使用该类时,就会为其分配内存空间直到该类被卸载才会进行资源回收!
关于static,有一道笔试题,不妨一看。
- class Test{
- private int m;
- public static void fun(){
- //some code...
- }
- }
- 如何使成员变量m被函数fun()直接访问
- A.将private int m改为protected int m
- B.将private int m改为public int m
- C.将private int m改为static int m
- D.将private int m改为int m
本题选C
17.Java集合:集合类存放于java.util包中,java集合主要可以划分为四个部分,List、Set、Map、工具类(Iterator迭代器、Enumeration枚举类、Arrays和VCollections)。java的集合类主要由两个接口派生而来,Collection和Map。在导入Set和List类时,方法是import java.util.Set和import java.util.List。但是注意Map和Collection都是借口,不能像Set类和List一样类导入。该怎么导入呢?例如我们要导入下面Colletion接口图中的TreeSet这个类,或者Map接口HashMap类,可以这样导入
- Map map=new HashMap();//import java.util.HashMap;和import java.util.Map;
- Collection col=new TreeSet();//import java.util.Collection;和import java.util.TreeSet;
分别来看一下这两个接口的体系
Colletion接口
Map接口
这个是总的结构图
(1)Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。但是却让其被继承产生了两个接口,就是Set和List。Set中不能包含重复的元素。List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式。
(2)Map是Java.util包中的另一个接口,它和Collection接口没有关系,是相互独立的,但是都属于集合类的一部分。Map包含了key-value对。Map不能包含重复的key,但是可以包含相同的value。
(3)Iterator,所有的集合类,都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含以下三种方法:
1.hasNext()是否还有下一个元素。
2.next()返回下一个元素。
3.remove()删除当前元素。
(4)ArrayList和LinkedList在用法上没有区别,但是在功能上还是有区别的。LinkedList经常用在增删操作较多而查询操作很少的情况下,ArrayList则相反。
(5)Map集合,实现类:HashMap、Hashtable、LinkedHashMap和TreeMap
HashMap是最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的。
Hashtable,Hashtable与HashMap类似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率较低。
LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢,有HashMap的全部特性。
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的。
有关集合,有一个例子特别好
- package knowledgeAboutColletion;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Iterator;
- public class HashSetTest {
- public static void main(String args[]){
- /*1.Collection<String>:泛型接口,这里的泛型String,所以添加的元素只能是String类型
- *2.ArrayList属于继承Collection接口的类,这个属于多态的向上转型
- *3.list属于接口,它有五种方法,add、remove、isEmpty、iterator、size*/
- Collection<String> list=new HashSet<>();//打印结果a,abc。Set集合不允许重复。
- list.add("abc");//添加字符串
- list.add("a");
- list.add("abc");
- /*Iterator迭代器,有三种方法
- *next():获得序列的下一个元素
- *hasNext():序列中是否还有元素
- *remove():将迭代器新返回的元素删除*/
- Iterator<String> it=list.iterator();
- while(it.hasNext()){
- String str=it.next();
- System.out.println(str);
- }
- }
- }
如果是List集合,则不一样,可以重复。
- package knowledgeAboutColletion;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Iterator;
- public class HashSetTest {
- public static void main(String args[]){
- Collection<String> list=new LinkedList<>();//打印结果abc,a,abc。List集合可以重复。
- list.add("abc");
- list.add("a");
- list.add("abc");
- Iterator<String> it=list.iterator();
- while(it.hasNext()){
- String str=it.next();
- System.out.println(str);
- }
- }
- }
这里把ArrayList改成LinkedList效果差不多,两者的区别百度一下,会有很多文章,同理上面的TreeSet和HashSet。暂时不细分同一接口下不同继承类的差别。
如果上面的Collection没有泛型呢?
- package knowledgeAboutColletion;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.TreeSet;
- public class HashSetTest {
- public static void main(String args[]){
- HashSetTest t=new HashSetTest();
- Collection list=new HashSet<>();//打印结果a,abc,Set集合不允许重复
- list.add("abc");
- list.add("a");
- list.add("abc");
- list.add(t);//添加对象,由于之前Collection泛型String,所以不能添加对象t,但是可以添加t.toString
- Iterator<String> it=list.iterator();
- while(it.hasNext()){
- String str=it.next();
- System.out.println(str);
- }
- }
- }
打印结果
- a
- abc
- Exception in thread "main" java.lang.ClassCastException: knowledgeAboutColletion.HashSetTest cannot be cast to java.lang.String
- at knowledgeAboutColletion.HashSetTest.main(HashSetTest.java:24)
对象t可以增加到集合中,但是无法打印出来。
Map集合的实例
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- public class HashSetTest {
- public static void main(String args[]){
- /*1.创建Map接口实例,这里泛型,并且用了两个泛型,这样泛型,后面put方法中填入的key-value只能是String类型
- * 如果没有这个泛型,可以是任何类型的
- 2.Map接口的六大方法
- (1)put(K key,V value):向集合中添加指定的key与value的映射关系
- (2)containsKey
- (3)containsValue
- (4)get
- (5)keySet:返回所有key对象形成的Set集合
- (6)values:返回所有key对象形成的Collection集合*/
- Map<String,String> map=new HashMap<>();
- map.put("01", "jason");//put方法需要两个
- map.put("02", "shu");
- Set<String> set=map.keySet();
- //iterator方法,Collection集合的方法,返回在此Collection的元素上进行迭代的迭代器
- Iterator<String> it1=set.iterator();
- System.out.println("key集合中的元素");
- //整个过程,从Map中提取key→将key转换为Set集合→为Set集合创建迭代器(因为要遍历)
- while(it1.hasNext()){
- System.out.println(it1.next());
- }
- Collection<String> col=map.values();//解释如上
- Iterator<String> it2=col.iterator();
- System.out.println("values集合中的元素");
- while(it2.hasNext()){
- System.out.println(it2.next());
- }
- }
- }
18.类的封装:封装是一种隐藏信息的技术,是将一个系统中的结构和行为通过类来划分的过程。即通过定义一组类,将特定的数据组合到某一个类中,形成一个整体,将该隐藏的数据进行保护,只对外暴露这些数据的访问的方法。封装代码有两个好处:(1)代码使用者无需考虑实现细节就能直接使用它,同时不用担心不可预料的副作用,别人不能随便修改内部结构(2)在外部接口保持不变的情况下,自己可以修改内部的实现。Java是通过访问控制关键字来实现的信息隐藏的,一共有三个关键字:public、protected和private。如果要隐藏一个类的成员变量,只要在该成员变量的前面加上private,这样外部就无法直接通过类的实例来访问这些成员变量了。
- package com.tianmaying.domain;
- public class Post {
- int id;
- int title;
- public long getId() {
- return id;
- }
- public void setId(long id) {
- this.id = id;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- }
使用get和set方法是为了程序的封装,为了其它的类可以使用(设置和获取)该类的私有方法。为什么要用get和set方法而不是用直接用public呢?譬如写个基类Base,然后有人继承了Base:
- public class Base {
- public String[] data;
- }
- class Sub extends Base{
- public void show(){
- System.out.println(Arrays.toString(this.getData()));
- }
- }
可是有一天你发觉用ArrayList更好,你就把Base改成:
- public class Base {
- //public String[] data;
- public ArrayList data;
- }
然后所有Base的子类都无法编译,直接调用到子类data域的类也无法编译。回过头来想,如果当初Base的data域是private,由get/set来访问,那么你可以轻松的修改Base, 子类无需改动:
- public class Base {
- //private String[] data;
- private ArrayList<String> data;
- public String[] getData() {
- return (String[]) data.toArray();
- }
- public void setData(String[] data) {
- this.data = new ArrayList<String>(Arrays.asList(data));
- }
- }
顺便说一下,Eclipse有自动生成标准get/set函数的功能,所以生成get/set是很容易的事情,不要为了方便把成员都变成public。
19.类的继承:继承使用extends关键字,Java允许一个类仅能继承一个其它类,即一个类只能有一个父类,这个限制被称做单继承性。后面将会学到接口(interface)的概念,接口允许多继承。
- class People{
- String name;
- int age;
- int height;
- void say(){
- System.out.println("我的名字是 " + name + ",年龄是 " + age + ",身高是 " + height);
- }
- }
定义一个Teacher类来继承People类
- class Teacher extends People{
- String school; // 所在学校
- String subject; // 学科
- int seniority; // 教龄
- void say(){// 覆盖 People 类中的 say() 方法
- System.out.println("我叫" + name + ",在" + school + "教" + subject + ",有" + seniority + "年教龄");
- }
- void lecturing(){
- System.out.println("我已经" + age + "岁了,依然站在讲台上讲课");
- }
- }
(1)name和age变量虽然没有在 Teacher 中定义,但是已在People中定义,可以直接拿来用。
(2)Teacher是People的子类,People是Teacher类的父类。
(3)子类可以覆盖父类的方法。
(4)子类可以继承父类除private以外的所有的成员,不能继承private的方法和变量,这也是封装的原理。
(5)构造方法不能被继承。
20.super关键字:super 关键字与 this 类似,this 用来表示当前类的实例,super 用来表示父类。super 关键字的功能:
(1)调用父类中声明为private的变量。
(2)点取已经覆盖了的方法。
(3)作为方法名表示父类构造方法。
- public class Demo{
- public static void main(String[] args) {
- Dog dog = new Dog();
- dog.move();
- }
- }
- class Animal{
- private String desc = "Animals are human's good friends";
- // 必须要声明一个 getter 方法
- public String getDesc() {
- return desc;
- }
- public void move(){
- System.out.println("Animals can move");
- }
- }
- class Dog extends Animal{
- public void move(){
- super.move(); // 调用父类的方法,super可以理解为父类对象
- System.out.println("Dogs can walk and run");
- // 通过 getter 方法调用父类隐藏变量
- System.out.println("Please remember: " + super.getDesc());
- }
- }
打印结果:
- Animals can move
- Dogs can walk and run
- Please remember: Animals are human's good friends
21.final关键字:一个变量可以声明为final,这样做的目的是阻止它的内容被修改。这意味着在声明final变量的时候,必须初始化它,通常情况下,我们会使用final来定义一些常量。
22.在面向对象的领域一切都是对象,所有的对象都是通过类来描述的。如果我们要定义的一个类没有足够的信息来描述一个具体的对象,还需要其他的具体类来支持,这个时候我们可以考虑使用抽象类。在类定义的前面增加abstract关键字,就表明一个类是抽象类。抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
abstract关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。声明抽象方法会带来以下两个结果:(1)如果一个类包含抽象方法,那么该类必须是抽象类。(2)任何子类必须重写父类的抽象方法,否则就必须声明自身为抽象类。
一般情况下,我们将一个类声明为abstract的,是因为它包含了没有具体实现的抽象方法。比如说我们给Graph类增加一个求面积的方法area(),因为我们不知道图形的形状,我们是无法给出实现的,只能交给特定的子类去实现,这时我们只能将area()声明为abstract的,代码如下:
- abstract class Graph {
- String name;
- public Graph(){}
- public Graph(String name) {
- this.name = name;
- }
- public void show() {
- System.out.println("I'm a graph");
- }
- public abstract double area();
- }
这时Rectangle类就必须给出area()方法的实现,否则它自己也必须用abstract修饰。
- class Rectangle extends Graph{
- public double area() {
- return width * height;
- }
- }
23.接口:与抽象类类似的一个重要概念是接口。接口(Interface)是一组抽象方法的集合。接口中定义的方法没有方法体,它们以分号结束。接口也和抽象类一样,无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。编写接口和编写类的方式是大体上是类似的,一个接口可以有多个方法,代码保存在以接口命名且以.java结尾的文件中。接口使用interface关键字进行定义。比如我们定义一个Animal接口:
- interface Animal {
- void eat();
- void sleep();
- }
这个接口包含了两个抽象方法:eat()和sleep()。接口中的方法都是外部可访问的,因此我们可以不需要用public修饰。接口中也可以声明变量,一般是final和static类型的,要以常量来初始化,实现接口的类不能改变接口中的变量。比如我们可以在Animal接口增加一个成员变量TIMES_OF_EATING,表示动物每天吃饭的次数。接口访问权限有两种:public权限和默认权限,如果接口的访问权限是public的话,所有的方法和变量都是public。默认权限则同一个包内的类可以访问。一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。比如我们可以定义TerrestrialAnimal接口,表示陆栖动物,它继承自Animal接口,同时还具有run()方法。
- interface TerrestrialAnimal extends Animal {
- void run();
- }
接口实现:类使用implements关键字实现接口。在类声明中,implements关键字放在class声明后面。接口支持多重继承,即一个类可以同时实现多个接口。
- class Cat implements Animal {
- public void eat() {
- System.out.println("eat");
- }
- public void sleep() {
- System.out.println("sleep");
- }
- }
类需要对接口中的每一个方法都给出实现。我们可以使用接口类型来声明一个变量,那么这个变量可以引用到一个实现该接口的对象。比如:
Animal cat = new Cat()
通过接口来声明变量,可以让程序更具有扩展性,因为将来我们更方便替换接口的实现。
24.抽象类和接口的比较:
相同点:
都不能被实例化
都包含抽象方法,这些抽象方法用于描述系统能提供哪些服务,而这些服务是由子类来提供实现的
在系统设计上,两者都代表系统的抽象层,当一个系统使用一棵继承树上的类时,应该尽量把引用变量声明为继承树的上层抽象类型,这样可以提高两个系统之间的松耦合
不同点:
在抽象类中可以为部分方法提供默认的实现,从而避免在子类中重复实现它们;但是抽象类不支持多继承。接口不能提供任何方法的实现,但是支持多继承。
接口代表了接口定义者和接口实现者的一种契约;而抽象类和具体类一般而言是一种is-a的关系,即两者在概念本质上是不同的。
25.Java异常:异常定义了程序中遇到的非致命的错误,比如如程序要打开一个不存的文件、网络连接中断、除零操作、操作数越界、装载一个不存在的类等情况。我们将可能出现异常的代码通过try/catch代码进行了处理,当异常发生时,系统能够继续运行,而没有意外终止。当try代码块中的语句发生了异常,程序就会跳转到catch代码块中执行,执行完catch代码块中的程序代码后,系统会继续执行catch代码块之后的代码,try代码块中发生异常语句后的代码则不会再执行。
26.throws关键字:下面是一个代码实例。
- package com.tianmaying;
- public class HelloWorld {
- private static void fun() {
- int x = 5 / 0;
- System.out.println(x);
- }
- public static void main(String[] args) {
- try {
- fun();
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("program is still running here!");
- }
- }
面对的是一个fun()函数,如何知道这个函数是否需要调用添加try/catch处理呢? 在Java中,这个问题是交给被调用的方法的实现者来解决的。在这个例子中,定义fun()方法的时候,我们在方法参数列表后面增加一个throws关键字,然后增加这个方法可能抛出的异常,这种情况下调用者就必须使用try/catch进行处理了,否则编译将无法通过。因此将代码改为:
- public class HelloWorld {
- private static void foo() throws Exception {
- int x = 5 / 0;
- System.out.println(x);
- }
- public static void main(String[] args) {
- try {
- foo();
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("program is still running here!");
- }
- }
如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理,则此方法应声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。也就是如果程序中的异常没有用try/catch捕捉异常以及处理异常的代码,我们可以在程序代码所在的函数(方法)声明后用throws声明该函数要抛出异常,将该异常抛出到该函数的调用函数中。
Exception类是java.lang.Throwable类的子类。在实际应用中,我们一般是使用Exception的子类来描述特定的异常的。Exception类是所有异常类的父类,Java语言为我们提供了许多Exception类的子类,分别对应不同的异常类型,例如:
ArithmeticException(在算术运算中发生的异常,如除以零)
NullPointerException(变量还没有指向一个对象,就引用这个对象的成员)
ArrayIndexOutOfBoundsException(访问数组对象中不存在的元素)
使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。在程序中使用自定义异常类,大体可分为以下几个步骤:(1)创建自定义异常类(2)在方法中通过throw关键字抛出异常对象(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作(4)在出现异常方法的调用者中捕获并处理异常。
- public class BlogAppException extends Exception {//继承Exception异常类
- private static final long serialVersionUID = 1L;
- private String command;// 可以给自定义异常增加成员变量,用以保存额外的异常信息
- public BlogAppException(String command) {
- this.command = command;
- }
- public String toString(){
- return "Exception happened when executing command " + command;
- }
- }
我们来增加一个可以抛出这个异常的方法,并且在main方法中进行调用:
- public class HelloWorld {
- private static void bar() throws BlogAppException {
- System.out.println("let's assume BlogAppException happened when executing `create` command");
- // 为了演示,这里我们假设执行create命令时,抛出了异常
- throw new BlogAppException("create");
- }
- private static void foo() throws ArithmeticException {
- int x = 5 / 0;
- System.out.println(x);
- }
- public static void main(String[] args) {
- try {
- foo();
- bar();
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("program is still running here!");
- }
- }
在catch多个异常时,如果使用catch(Exception e)语句,那么它不能放在其他catch语句的前面,否则后面的catch永远得不到执行,因为Exception是所有异常的父类。另外关于异常,在继承时需要注意两点:(1)一个方法被覆盖时,覆盖它的方法必须扔出相同的异常或异常的子类。(2)如果父类抛出多个异常,那么重写(覆盖)方法必须扔出那些异常的一个子集,也就是说,不能扔出新的异常。
在try/catch语句后,我们还可以有个finally语句,finally语句中的代码块不管异常是否被捕获总是要被执行的。finally还有一个特殊之处在于,即使try代码块和catch代码块中使用了return语句退出当前方法或break跳出某个循环 ,相关的finally代码块都要执行。finally中的代码块不能被执行的唯一情况是:在被保护代码块中执行了System.exit(0)。
27.Java IO:下面的代码通过FileInoutStream和FileOutputStream来完成文件内容的拷贝:
- import java.io.*;
- public class CopyFileByte {
- public static void main(String args[]) throws IOException
- {
- FileInputStream in = null;
- FileOutputStream out = null;
- try {
- in = new FileInputStream("input.txt");
- out = new FileOutputStream("output.txt");
- int c;
- while ((c = in.read()) != -1) { //返回-1 表示达到文件结尾,首先判断是否到文件结尾,没有的话赋值给c
- out.write(c);
- }
- }finally {
- if (in != null) {
- in.close();
- }
- if (out != null) {
- out.close();
- }
- }
- }
- }
InputStream和OutputStream是字节流处理,最小单位是一个字节8bits,而Java IO中还有一种字符流,它们处理的单位是16bits。
- import java.io.*;
- class ConsoleInOut {
- public static void main(String args[])throws IOException{
- InputStreamReader isr = null;
- try {
- isr = new InputStreamReader(System.in);//控制台输入,而不是标准输入类似于上面的"input.txt"
- System.out.println("Enter characters, 'q' to quit.");
- char c;
- do {
- c = (char) isr.read();//第一次键盘键入q的时候,还是会输出q
- System.out.println(c);
- } while(c != 'q');
- }finally {
- if (isr != null) {
- isr.close();
- }
- }
- }
- }
在这两个语句当中,我们可以看到对异常的处理都是用try...finally,而不是try...catch...finally的形式,那什么时候使用try-finally,什么时候使用try-catch-finally呢?很显然这取决于方法本身是否能够处理try中出现的异常。如果自己可以处理,那么直接catch住,不用抛给方法的调用者;如果自己不知道怎么处理,就应该将异常向外抛,能够让调用者知道发生了异常。即在方法的签名中声明throws可能出现而自己又无法处理的异常,但是在方法内部做自己应该的事情。
28.数组和集合的区别:(1)数组声明容纳元素的类型,集合不声明 (2)数组是静态的,大小固定,集合不固定 (3)数组存放的类型只能是一种,集合可以有多种,不加泛型时类型为Object (4)数组由于是java内置的数据类型,执行效率快 (5)ArrayList就是基于数组创建的容器类
29.List是一个接口,而ArrayList是List接口的一个实现类。 ArrayList类继承并实现了List接口。因此,List接口不能被构造,也就是我们说的不能创建实例对象,但是我们可以像下面那样为List接口创建一个指向自己的对象引用,而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用。
30.多态:理解多态前先了解一下重载和覆盖这两个概念。
一个方法名,参数不同,这叫方法重载。(Overload)
- void foo(String str);
- void foo(int number);
父类与子类有同样的方法名和参数,这叫方法覆盖。(Override)
- class Parent {
- void foo() {
- System.out.println("Parent foo()");
- }
- }
- class Child extends Parent {
- void foo() {
- System.out.println("Child foo()");
- }
- }
父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现,这叫多态。
- Parent instance = new Child();
- instance.foo(); //==> Child foo()
31.Object类:Object类在Java中被定义为一个顶级父类,它是任何类的父类,我们可以显示的继承它,也可以隐式继承,如以下实例
- public class Dog extends Object{
- }
与
- public class Dog{
- }
二者完全相同,Object类包含如下方法,1.equals(Object obj) 2.finalize() 3.getClass 4. hashCode() 5. notify 6. notifyAll() 7. wait() 8. Clone() 9. toString()由于Object类是任何类的父类,也就是说对Java中任意一个对象,都是可以用这九种方法的。
32.IO流:主要搞清楚InputStream,Reader,InputStreamReader,FileInputStream,BufferedReader,FileReader,BufferedInputStream.DataInputStream.
所有输入流都是InputStream(字节输入流)和Reader(字符输入流)的子类,InputStreamReader是字节流和字符流之间的桥梁,能将字节流输出为字符流。熟悉了这两点其他的就很好说了,其他的输入流都是作为它们的子类。
InputStream:字节输入流,在搞清楚字节输入流之前,我们需要搞清楚字节,所谓字节(Byte),指的是一种计量单位,表示数据量多少。例如“11数3A+、”所占的字节数为9,怎么来的呢?阿拉伯数字和英文字符占的字节数为1,中文字符“数”和中文符号“、”占的字节数为2,所以字节数为9。
Reader:字符是指计算机中使用的文字和符号,比如“1、2、3、A、B、C、~!·#¥%……—*()——+、”等等。
标签:Java,String,int,void,接口,基础知识,out,public,入门 来源: https://www.cnblogs.com/java0/p/13485416.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。