对象:万物皆对象,所有的东西都是对象,对象是一个自包含的实体,用一组可识别的特性和行为来标识。
类:是具有相同属性和功能的对象的抽象集合
实例:就是一个真实的对象
实例化:创建对象的过程,使用new关键字来创建
public void Test() { Cat cat = new Cat();//将Cat类实例化 }
'Cat cat = new Cat();'做了两件事
Cat cat;//声明一个Cat的对象,对象名为cat cat = new Cat();//将此cat对象实例化
构造方法又叫构造函数,就是对类进行初始化。与类同名,无返回值,不需要void,在new的时候调用。
Cat cat = new Cat()
其中,Cat()就是构造方法。
所有类都有构造方法,不定义构造方法系统会默认生产空的构造方法。定义构造方法,则默认的构造就方法会消失。
public class Cat { //声明Cat类的私有字符串变量name private String name = ""; //定义Cat类的构造方法,参数是输入一个字符串。 public Cat(String name) { this.name = name;//将参数赋值给私有变量name } }
方法重载提供创建同名的多个方法的能力,但是这些方法需使用不同的参数类型,不只构造方法可以重载,普通方法也可以重载。
方法名相同,参数类型或个数必须要有所不同。
方法重载可在不改变原方法的基础上,新增功能。
public class Cat { private String name = ""; public Cat(String name) { this.name = name; } //将构造方法重载 public Cat() { this.name = "无名"; } }
属性:是一个方法或一对方法,在调用它的代码看来,它是一个字段,即属性适合于以字段的方式使用方法调用的场合。
字段:是存储类要满足其设计所需要的数据,字段都是与类相关的变量。
//声明一个内部字段,private,默认为3 private int shoutNum = 3; //ShoutNum属性,注意是public public int ShoutNum { //get表示外界调用时可以得到shoutNum的值 public int get(){ return shoutNum; } //set表示外界可以给内部的shoutNum赋值 public void set(int value){ shoutNum = value; } }
属性有两个方法,get和set。
get:访问器返回与声明的属性相同的数据类型,调用时可以得到内部的字段的值或引用。
set:调用属性时可以给内部的字段或引用赋值。
public:表示它所修饰的类成员可以允许其它任何类来访问,俗称公有的。
private:表示只允许同一个类中的成员访问,其它类包括它的子类无法访问,俗称私有的。
通常字段都是private,即私有变量(一般是首字母小写或前加‘_’),而属性都是public,即公有变量(首字母大写)。
final
- 修饰变量:修饰变量时必须赋初值且不呢改变,修饰引用变量不能再指向其他对象。
- 修饰方法:方法前面加上final关键字,代表这个方法不可被子类重写。
- 修饰类:表示这个类不能被继承,类中的成员可以根据需要设为final,final类中的所有成员方法都会被隐饰地指定为final方法。
注:类的private方法会被隐饰地指定为final
protected:继承的子类可以对基类(父类)有完全访问权。对子类公开,不对其它类公开。
每个对象都包含它能进行操作所需的所有信息,因此对象不必依赖其它对象来完成自己的操作,能够避免对象属性赋值的随意性。
封装的好处:
- 良好的封装能减少耦合(相互作用相互影响的关系)。
- 类内部的实现可以自由地修改。
- 具有清晰的对外接口。(对外的属性和方法)set和get方法。
this关键字是对当前内的简化。
提供专门对外的set和get方法对属性进行设置,而不能用类.属性的方法修改值。
public class Student{ private int age;//age属性私有化 public Student(int age){ this.age = age; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } }
java只支持单继承,不允许多继承。
子类继承父类:
- 子类拥有父类所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类无法访问,只是拥有。
- 子类拥有自己的属性和方法,即子类可以在父类的基础上做扩展。
- 子类可以用自己的方式重写父类的方法。
package Test; class Students { int age;//id属性私有化 String name;//name属性私有化 Students(int age,String name){ this.age = age; this.name = name; } public void printInfo() { System.out.println("父类方法 年龄:"+age+" 姓名:"+name); } } class Student extends Students{ Student(int age, String name) { super(age, name); } //重写父类同名方法 @Override public void printInfo() { System.out.println("子类方法 年龄:"+age+" 姓名:"+name); } //使用super调用父类的方法 public void FatherprintInfo() { super.printInfo(); } } public class test { public static void main(String[] args) { // TODO Auto-generated method stub Student s2 = new Student(19,"张三"); s2.printInfo(); s2.FatherprintInfo(); } } //子类方法 年龄:19 姓名:张三 //父类方法 年龄:19 姓名:张三
继承使得所有子类公共的的部分都放在了父类,使得代码得到了共享,就可以避免重复,继承使得修改和扩展继承而来的实现都较为容易。
继承也是有缺点的,那就是父类做出修改,子类就不得不进行改变。另外,继承也会破坏包装,父类实现的细节暴露给子类。
总结:只有合理的应用继承才能发挥好的作用。例如猫继承动物,而动物不能继承猫。
多态表示不同的对象执行相同的操作,但是要通过自己的实现代码来执行。
注意点:
编译时多态:
- 重载(overload)多个同名的不同方法。
运行时多态:
- 覆盖(override),子类对父类方法进行覆盖(重写)。
- 动态绑定--也称为虚方法调用,正真的方法在运行时才确定。
- 在调用方法时,程序会正确地调用子类对象的方法。
1.多态成员变量:编译运行看左边。
People p = new Student(); System.out.println(p.name)//p是People中的值,只能取到父类中的值。
2.多态成员方法:编译看左边,运行看右边。
People p1 = new Student(); System.out.println(p1.printInfo())//p1的表面上类型是People,但实际上是Student,所以调用的是重写后的方法。
用于判断某个对象是否属性某种数据类型。
返回类型为布尔类型。
People p1 = new Student(); System.out.println(p1 instancof Student); //true
将子类对象赋值给父类变量,称之为向上转型。
//People[] people = {new Student(19,"张三"), new Teacher(30,"老师A")}; People people[];//声明一个人类数组 people = new People[1];//实例化最多两个人类对象 //向上转型 people[0] = new Student(19,"张三"); people[1] = new Teacher(30,"老师A"); //foreach遍历对象 for(People item : people) { item.printInfo(); } //年龄:19 姓名:张三 //年龄:30 姓名:老师A
将父类变量转换为子类变量,称之为向下转型。向下转型格式如下:
子类类型 变量名 = (子类类型) 父类类型的变量 for(int i=0;i<people.length;i++){ if(people[i] instanceof Student){ //向下转型 Student student = (Student) people[i]; }else if(people[i] instanceof Teacher){ Teacher teacher = (Teacher) people[i]; }else{ System.out.println("程序错误。"); } }
仔细观察,你会发现,People类其实根本不能实例化,一个学生长什么样子,可以想象。new People;即实例化一个人,一个人长什么样?
People是一个抽象的名词,没有其具体对象与之对应。
Java运行把类和方法声明为abstract,即抽象类和抽象方法。
abstract class People{//加abstract关键字,表面抽象类。 ...... //在方法返回值前加abstract表明此方法是抽象方法,抽象方法没有方法体,直接在括号后面加上";" protected abstract void printInfo(); }
抽象类注意点:
让抽象类拥有尽可能多的共同代码,拥有尽可能少的数据。
抽象类通常代表一个抽象的概念,它提供一个继承的出发点,当设计一个新的抽象类时,一定是用来继承的,所有在一个继承关系形成的等级结构里,树叶节点应当是具体类。而树叶节点均应当是抽象类。
接口就是把隐式公共方法和属性组合起来,以封装特定功能的一个集合,一旦类实现了接口,类就可以职称接口所指定的所有属性和成员,声明接口的语法和抽象类完全相同,但不允许提供接口中任何成员的执行方式。所以接口不能实例化,不能有构造方法和字段;不能有修饰符(如public,private等);不能声明虚拟的或静态的等。还有实现接口的类就必须要属性接口中的所有方法和属性。
一个类可以支持多个接口,多个类也可以支持相同的接口。接口的命名,前面要加一个大写的字母'I',这是规范。
接口用interface声明,而不是class,接口名称前要加‘I’,接口中的方法或属性前面不能有修饰符、方法没有方法体。
//声明一个IPeople接口,此接口有一个printInfo方法 interface IPeople{ void printInfo(); }
使用接口实现学生类
class Student implements IPeople{ public void printInfo(){ System.out.println("运行正确。"); } }
抽象类可以给出一些成员的实现,接口却不包含成员的实现,抽象类的抽象成员可被子类部分实现,接口的成员需要实现类完全实现,一个类只能继承一个抽象类,但可实现多个接口等。
区分:
泛型是具有占位符(类型参数)的类、结构、接口和方法,这些占位符是类、结构、接口和方法所储存或使用的一个或多个类型的占位符。泛型集合类可以将类型参数用作它所存储的对像的类型的占位符;类型参数作为其字段和其方法的参数类型出现。
IList arrayPeople;//声明一个集合变量,可以用接口IList,也可以直接声明“ArrayList arrayPeople;”
用法就是在IList和List后面加'
//声明一泛型集合变量,用接口IList,注意:IList表示此集合变量只能接受People类型,其它类型不接受,也可以直接声明“List ” IList<People> arrayPeople; //实例化List对象,需要指定List<T>的'T'是People arrayPeople = new List<People>();
泛型有三种使用的方式,分别为:泛型类、泛型接口、泛型方法。
public class People<T>{ //T stands for "Type" private T t; public void set(T t){this.t = t;} public T get(return t); }
java泛型详解
10 道 Java 泛型面试题(opens new window)
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明,配置的功能。注解不会也不呢影响代码的实际逻辑,仅仅起到辅助性的作用。
注解 Annotation 实现原理与自定义注解例子(opens new window)
可以获取任意一个类的所有属性和方法,还可以调用这些属性和方法。
Java反射主要提供以下功能:
重点:是运行时而不是编译时。
我们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。
但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。
这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。
在Java中,所有的异常都有一个共同的祖先java.lang包中的Throwable类,Throwable类有两个重要的子类Error(错误)和Exception(异常)。其中Error用来表示JVM(Java虚拟机)无法处理的错误,Exception又分为两种:
public string getMessage()//返回异常发生时的简要描述。 public string toString()//返回异常发生时的详细信息。 public string getLocalizedMessage()//返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回结果相同。 public void printStackTrace()//在控制台上打印Throwable对象封装的异常信息。
try块:用于捕获异常,后面可以接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch块:用于处理try捕获到的异常。
finally块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。
在下面三种特殊情况下,finally块不会被执行:
注意:当try语句和finally语句中都有return语句时,在方法返回之前,finally语句的内容将被执行,并且finally与的返回值会覆盖原始的返回值,如下:
public class Test{ public static int f(int value){ try{ return value*value; }finally{ if(value == 2) return 0; } } }
如果调用f(2),返回值将是0,因为try语句的返回值被finally语句的返回值覆盖。
《Effecitve Java》中明确指出:
面对必须要关闭的资源,我们总是应该优先使用try-with-resources而不是try-finally。随之产生的代码更简短,更清晰,产生的异常对我们也更有用。try-with-resources语句让我们更简短清晰,产生的异常对我们更有用。try-with-resources语句让我们更容易编写必须要关闭的资源的代码,若采用try-finally则几乎做不到这点。
Java中类似于InputStream、OutputStream、Scanner、PrintWriter等的资源都需要我们调用close()方法来手动的关闭。
使用try-catch-finally语句实现:
//读取文本文件的内容 Scanner scanner = null; try{ scanner = new Scanner(new File("D://read.txt")); while(scanner.hasNext()) System.out.println(scanner.nextLine()); }catch (FileNotFoundException e){ e.printStackTrace(); }finally{ if(scanner != null) scanner.close(); }
使用Java 7之后的try-with-resources语句改造上面的代码:
try (Scanner scanner = new Scanner(new File("D:\\read.txt"))){ while(scanner.hasNext()) System.out.println(scanner.nextLine()); }catch (FileNotFoundException e){ e.printStackTrace(); }
通过使用分号分隔符,可以在try-with-resources块中声明多个资源。
try(BufferredInputStream bin = new BufferredInputStream(new FileInputStream(new File("test.txt"))); BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))){ int b; while((b = bin.read()) != -1) bout.write(b); }catch (IOException e) { e.printStackTrace(); }