给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-parentheses
class Solution {
public boolean isValid(String s) {
Stack<Character> stack=new Stack<>();
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(c=='('||c=='['||c=='{'){stack.push(c);}
else if(stack.isEmpty()||c==')'&&stack.pop()!='('||c==']'&&stack.pop()!='['||c=='}'&&stack.pop()!='{'){return false;}
}
return stack.isEmpty();
}
}
二. Java运行时数据区都有哪几块组成
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为多个数据区域,有的区域区域随着虚拟机进程的启动而一直存在,有些则是随着用近乎线程的启动和结束而建立和销毁。
1.程序计数器
程序计数器可以看作是当前线程所执行的字节码行号指示器,也是程序控制流的指示器,用来完成分支,循环,跳转,异常处理,线程恢复等基础操作,每条线程都有自己独立的程序计数器,所以称它为线程私有。
2.Java虚拟机栈
Java虚拟机描述的是Java方法执行的线程内存模型:每个方法大被执行的时候,Java虚拟机都会同步创建一个栈帧用于储存局部变量表,操作数栈,动态连接,方法出口等信息。每个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中入栈出栈的过程。并且它也是线程私有的,生命周期与线程相同。
3.本地方法栈
本地方法栈与虚拟机栈发挥的作用非常的相似,其区别在于虚拟机栈为虚拟机执行的Java方法(字节码)服务,而本地方法栈则是为虚拟机使用到的本地方法(Native)服务,由于《Java虚拟机规范》并没有对本地方法栈中方法使用的语言,使用方式与数据结构进行强制规定,所以虚拟机可以根据需要自由实现它,甚至有些Java虚拟机( HotSpot )可以把本地方法栈和虚拟机栈合二为一。
4.Java堆
Java堆是被所有线程所共享的一块内存区域,用来存放对象实例以及数组的内存区域,是虚拟机所管理的内存最大的一块,并且可以处于物理上不连续的内存空间,但是逻辑上应该是被视为连续的。
5.方法区
方法区是各个线程共享的一块区域,它用来储存被虚拟机加载过的类型信息,常量,静态变量,即时编译器编译后的代码缓存等数据。别名为“ 非堆 ”,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,甚至还可以选择不进行垃圾回收。
6.运行时常量
是方法区的一部分,常量池表用来存放编译器生成的各种字面量与符号应用,这部分内容将在类加载后存放到方法区的运行时常量池中。除了保存Class文件中描述的符号引用外还会把由符号引用翻译出来的直接引用也储存在运行时常量池中。
三.类加载过程
加载
加载,是指Java虚拟机查找字节流(查找.class文件),并且根据字节流创建java.lang.Class对象的过程。这个过程,将类的.class文件中的二进制数据读入内存,放在运行时区域的方法区内。然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构。
类加载阶段:
(1)Java虚拟机将.class文件读入内存,并为之创建一个Class对象。
(2)任何类被使用时系统都会为其创建一个且仅有一个Class对象。
(3)这个Class对象描述了这个类创建出来的对象的所有信息,比如有哪些构造方法,都有哪些成员方法,都有哪些成员变量等。
验证
验证阶段作用是保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害。如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常。验证过程分为四个阶段:
文件格式验证:验证字节流文件是否符合Class文件格式的规范,并且能被当前虚拟机正确的处理。
元数据验证:是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范要求
字节码验证:主要是进行数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机。
符号引用验证:符号引用验证发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在解析阶段中发生。
准备
准备阶段为变量分配内存并设置类变量的初始化。在这个阶段分配的仅为类的变量(static修饰的变量),而不包括类的实例变量。对已非final的变量,JVM会将其设置成“零值”,而不是其赋值语句的值:pirvate static int size = 12;。那么在这个阶段,size的值为0,而不是12。但final修饰的类变量将会赋值成真实的值。
解析
解析过程是将常量池内的符号引用替换成直接引用。主要包括四种类型引用的解析。类或接口的解析、字段解析、方法解析、接口方法解析。
初始化
初始化,则是为标记为常量值的字段赋值的过程。换句话说,只对static修饰的变量或语句块进行初始化。
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
三.gc的理解
GC(即Garbage Collection,垃圾回收),在C++中,内存的释放是有程序员操作的,在JAVA中,new的对象一般存放在堆内存中,当一个对象不再被直接或间接的引用,或是当它的引用计数器的值为0时,那么此对象将被认为是垃圾,随着废弃对象的堆积可能会导致内存泄漏,而这一块垃圾就需要GC去参与回收。GC回收的区域主要集中在堆和方法区,在程序运行期间,这部分内存的分配和使用都是动态的