2020/08/03
考虑考算法岗的红海,正式打算下海Java算法岗了。
JVM: java虚拟机。
JDK:Java开发工具包
源文件:Hello.java ——>经过编译器得到字节码文件 Hello.class文件——>在经过解释器,从而实现运行。字节码文件是可以跨平台的。字节码文件可以通用,JVM 是特定于平台的.
文本编辑java:可以用txt文件完成java的编写,在cmd中进行到相应的文职,运行javac Helloworld.java
,这样会在相应位置生成一个Helloworld.class
文件。再次java Helloworld
。
这里javac
命令是对原始文件进行编译,java
的命令对字节码进行执行。
Java 语言定义了以下 4 种变量 :
static
关键字修饰,因此也称为非静态字段。需要通过 new 关键字实例化出对象,通过对象才能访问其实例变量(也称实例属性)。需要注意char
是单一字符,Java 中的 char 类型除了可表示标准的 ASCII 外,还可以表示一个 Unicode 字符;String
是字符串,并不是基本类型。需要注意的是,long 类型的值后面要以大写字母 L 或小写字母 l 结尾,long a = 10L
。需要注意的是,float 类型的值必须要以大写字母 F 或小写字母 f 结尾,float a = 1.2f
,也可以使用科学计数法double = d = 1.23e2
// 需要特别注意,String的是双引号,char是单引号
String name="爱慕课";
char sex='男';
java是支持自动类型转换,但是要求目标类型与源类型兼容,如double兼容int型。或者目标类型大于源类型,double的字节长度是大于int的。同时也是可以使用强制类型转换的,如,
double heightAvg1=176.2;
int heightAvg2 = (int)heightAvg1;
利用final定义常量:
常量的定义一般采用大写字母final PI = 3.014;
PS:使用文档注释时还可以使用 javadoc 标记,生成更详细的文档信息:
@author 标明开发该类模块的作者
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@param 对方法中某参数的说明
@return 对方法返回值的说明
@exception 对方法可能抛出的异常进行说明
这里主要说明一些和python中不太一样的
&&
这个是and||
这个是or!
这个是逻辑反布尔表达式 ? 表达式1 :表达式2
三元运算符,如果判断条件为真,执行第一个部分,否则执行第二个。String mark = (score>=60)?"及格":"不及格";
instanceof
将对象与指定类型进行比较,检查对象是否是一个特定类型(类类型或接口类型)。注意,instanceof 运算符不能用于操作基本数据类型// 格式
( Object reference variable ) instanceof (class/interface type)
boolean b = name instanceof String;
int[] scores = { 78, 93, 97, 84, 63 };
或者int[] scores = new int[]{ 78, 93, 97, 84, 63 };
nums.length
import java.util.Arrays
Arrays.sort(nums)
Arrays.toString(数组名);
for (int e:elements){
}
面向对象的三大特征:封装、继承、多态。
public
、private
、protected
,也可以省略(default)。public void sun(int... n)
。这中方法最后进来是一个int数组。当方法的参数列表有两个或两个以上参数时,可变参数一定要放在最后。将数组传递给可变参数列表。new object[]{a, b}
// 调用属性
对象名.属性名;
// 调用方法
对象名.方法名();
public
形式,方法名与类名同名。this
关键字的使用,表示当前实例。private
,保证不会在类外被访问。extends
继承:Java 中的继承为单一继承,也就是说,一个子类只能拥有一个父类,一个父类可以拥有多个子类。
另外,所有的 Java 类都继承自 Java.lang.Object
,所以 Object
是所有类的祖先类。子类一旦继承父类,就会继承父类所有开放的特征,不能选择性地继承父类特征
如果一个类从它的父类继承了一个方法,如果这个方法没有被标记为 final
或 static
,就可以对这个方法进行重写。重写的好处是:能够定义特定于子类类型的行为,这意味着子类能够基于要求来实现父类的方法。重写一般要加上标识,@override
。
方法重写规则:
方法重写和方法重载的区别
Java 中的方法重写(Overriding)是说子类重新定义了父类的方法。方法重写必须有相同的方法名,参数列表和返回类型。覆盖者访问修饰符的限定大于等于父类方法。
而方法重载(Overloading)发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。
super 是用在子类中的,目的是访问直接父类的变量或方法。注意:
super(name)
;一般放在static
之后。可以作用于子类,方法,变量。
final
作用于子类,这个类是无法别继承的。final
作用于方法,这个方法是无法被重写的。final
作用于变量,这个变量被初始化之后无法修改。在面向对象中最常用的多态性发生在当父类引用指向子类对象时。在面向对象编程中,所谓多态意指相同的消息给予不同的对象会引发不同的动作。换句话说:多态意味着允许不同类的对象对同一消息做出不同的响应。
实现多态的三个条件:1.满足继承关系;2.要有重写;3.父类引用指向子类对象。
例子:
在代码中,Pet dog = new Dog()
;、Pet cat = new Cat()
; 这两个语句,把 Dog 和 Cat 对象转换为 Pet 对象,这种把一个子类对象转型为父类对象的做法称为向上转型。父类引用指向了子类的实例也就实现了多态。子类的对象可以赋值给父类对象。
public void main(String[] args) {
// 分别实例化三个对象,并且保持其类型为父类Pet
Pet pet = new Pet();
Pet dog = new Dog();
Pet cat = new Cat();
// 调用对象下方法
pet.eat();
dog.eat();
cat.eat();
}
注意:不能将父类对象转换为子类类型,也不能将兄弟类对象相互转换。
为提高向下转型的安全性,先进行instanceof
的判断。
Pet pet = new Cat();
if (pet instanceof Cat) {
// 将父类转换为子类
Cat cat = (Cat) pet;
}
abstract
当某个父类只知道其子类应该包含什么方法,但不知道子类如何实现这些方法的时候,抽象类就派上用场了。使用抽象类还有一个好处,类的使用者在创建对象时,就知道他必须要使用某个具体子类,而不会误用抽象的父类,因此对于使用者来说,有一个提示作用。
子类在继承了抽象类之后,必须要重写方法。
一个抽象类不能直接实例化,但类的其他功能依然存在;既然不能被实例化,那么它必须被继承才能被使用。
abstract class Pet {
abstract void eat();
}
抽象方法不能是final
、static
和 native
的;并且抽象方法不能是私有的,即不能用 private
修饰。因为抽象方法一定要被子类重写,私有方法、最终方法以及静态方法都不可以被重写,因此抽象方法不能使用 private
、final
以及static
关键字修饰。而native
是本地方法,它与抽象方法不同的是,它把具体的实现移交给了本地系统的函数库,没有把实现交给子类,因此和abstract
方法本身就是冲突的。
interface
关键字 interface
修饰的class
就是一个接口。接口定义了一个行为协议,可以由类层次结构中任何位置的任何类实现。接口中定义了一组抽象方法,都没有具体实现,实现该接口的类必须实现该接口中定义的所有抽象方法。
public interface Person {
final String NAME = "我是Person接口中的常量";
void walk();
void run();
}
一个类是可以继承多个接口的。继承接口的关键字implements
。继承接口之后,要重写接口要求的方法。当一个实现类存在 extends
关键字,那么implements
关键字应该放在其后:public class MyClass extends SuperClass implements MyInterface
接口之间也是可以继承的,关键词extends
。值得注意的是,一个接口可以继承多个父接口。
接口中的默认方法与静态方法default
:实现类可以不实现默认方法和类方法,当然也可以重写,重写的方法不需要defult
。如果想要在实现类中调用接口的默认方法,可以使用接口名.super. 方法名 ()
的方式调用。
public interface Person {
void run();
default void eat() {
System.out.println("我是默认的吃方法");
}
}
静态方法:类中的静态方法只能被子类继承而不能被重写
,同样在实现类中,静态方法不能被重写。如果想要调用接口中的静态方法,只需使用 接口名.类方法名()
的方式即可调用:
接口的方法默认是 public ,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法;
接口中除了 static 、final 变量,不能有其他变量,而抽象类可以;
一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过 extends 关键字扩展多个接口;
接口方法默认修饰符是 public ,抽象方法可以有 public 、protected 和 default 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!);
从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。
Java 中的内部类可以分为 4 种:成员内部类、静态内部类、方法内部类和匿名内部类。
最简单的情况,class的内部生成了一个class。可以外部类是public
, 内部类是private
这样可以保证只能类内使用。我们可以通过 new 外部类().new 内部类()
的方式获取内部类的实例对象:
成员访问:可以在内部类的中访问外部类的成员属性;如果内部类中也存在一个同名成员,那么优先访问内部类的成员;这种情况下如果依然希望访问外部类的属性,可以使用外部类名.this.成员
的方式。
静态内部类的实例化,可以不依赖外部类的对象直接创建。记着这是一个类共享的,因此没必要纠结是哪个对象的。
只在方法中使用这个类,具有几个特点:局部内部类只能在方法内部使用;方法内不能定义静态成员;不能使用访问修饰符。
匿名内部类就是没有名字的内部类。使用匿名内部类,通常令其实现一个抽象类或接口。不能有修饰,也没有构造器。
1.为什么使用内部类?
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,
对于内部类都没有影响
1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:
(1)、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独。
(2)、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
(3)、创建内部类对象的时刻并不依赖于外围类对象的创建。
(4)、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
(5)、内部类提供了更好的封装,除了该外围类,其他类都不能访问。
2.内部类分类:
(一).成员内部类:
public class Outer{
private int age = 99;
String name = "Coco";
public class Inner{
String name = "Jayden";
public void show(){
System.out.println(Outer.this.name);
System.out.println(name);
System.out.println(age);
}
}
public Inner getInnerClass(){
return new Inner();
}
public static void main(String[] args){
Outer o = new Outer();
Inner in = o.new Inner();
in.show();
}
}
★★友情提示:
1.外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
2.如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字,如:Outer.this.name
(二).静态内部类: 是 static 修饰的内部类,
public class Outer{
private int age = 99;
static String name = "Coco";
public static class Inner{
String name = "Jayden";
public void show(){
System.out.println(Outer.name);
System.out.println(name);
}
}
public static void main(String[] args){
Inner i = new Inner();
i.show();
}
}
(三).方法内部类:其作用域仅限于方法内,方法外部无法访问该内部类
(1). 局部内部类就像是方法里面的一个局部变量一样,是不能有 public
、protected
、private
以及 static
修饰符的。
(2). 只能访问方法中定义的 final 类型的局部变量,因为:
当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,
直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量;
==>使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.
局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数;防止被篡改数据,而导致内部类得到的值不一致
/*
使用的形参为何要为 final???
在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,
也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,
毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解
和不可接受的,所以为了保持参数的一致性,就规定使用 final 来避免形参的不改变
*/
public class Outer{
public void Show(){
final int a = 25;
int b = 13;
class Inner{
int c = 2;
public void print(){
System.out.println("访问外部类:" + a);
System.out.println("访问内部类:" + c);
}
}
Inner i = new Inner();
i.print();
}
public static void main(String[] args){
Outer o = new Outer();
o.show();
}
}
(3). 注意:在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了 Effectively final 功能
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的
(四).匿名内部类:
(1). 匿名内部类是直接使用 new 来生成一个对象的引用;
(2). 对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用;
(3). 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;
(4). 匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;
(5). 匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
(6). 匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果
public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}