admin管理员组

文章数量:1593971

Algorithm:

/**
 * 20. Valid Parentheses
 * Easy
 * <p>
 * 3237
 * <p>
 * 153
 * <p>
 * Favorite
 * <p>
 * Share
 * Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
 * <p>
 * An input string is valid if:
 * <p>
 * Open brackets must be closed by the same type of brackets.
 * Open brackets must be closed in the correct order.
 * Note that an empty string is also considered valid.
 * <p>
 * Example 1:
 * <p>
 * Input: "()"
 * Output: true
 * Example 2:
 * <p>
 * Input: "()[]{}"
 * Output: true
 * Example 3:
 * <p>
 * Input: "(]"
 * Output: false
 * Example 4:
 * <p>
 * Input: "([)]"
 * Output: false
 * Example 5:
 * <p>
 * Input: "{[]}"
 * Output: true
 * Accepted
 * 664,170
 * Submissions
 * 1,792,734
 */
public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    Map<Character, Character> map = new HashMap<>();
    map.put('}', '{');
    map.put(']', '[');
    map.put(')', '(');
    for (char c : s.toCharArray()) {
        boolean flag = c == '[' || c == '(' || c == '{';
        if (flag) stack.push(c);
        else if (stack.isEmpty() || stack.pop() != map.get(c)) return false;
    }
    return stack.isEmpty();
}

Review:https://onezero.medium/youtubes-lgbtq-problem-is-a-business-model-problem-2b3cb3754b64 

YouTube’s LGBTQ Problem Is a Business-Model Problem

A new lawsuit highlights a basic injustice in YouTube’s ‘ad-friendly’ policies

 

 

YouTube wants to be a platform for self-expression for all kinds of people. It also wants to make piles of money selling and placing ads via automated systems with minimal human review.

It’s having trouble doing both.

This week, a group of LGBTQ video creators sued YouTube and parent company Google in federal court, alleging that it has systematically discriminated against their content. Specifically, the lawsuit accuses YouTube of filtering, demonetizing, and otherwise limiting videos that deal with LGBTQ identities, making it hard for their creators to reach a wide audience and make money. The suit alleges violations of free-speech protections and civil rights, among other statutes, and seeks class-action status.

The lawsuit cites, for example, videos about gender identity that YouTube demonetized; accounts focused on transgender issues that YouTube suspended; and a news and entertainment show aimed at the LGBTQ community to which YouTube declined to sell ads. At the same time that YouTube was restricting this content, the suit alleges, it was failing to moderate an avalanche of bigoted comments directed at the creators on their own video pages. The suit, which you can read in full here, also cites examples of videos mocking or criticizing LGBTQ people that YouTube appears not to have subjected to the same restrictions.

You don’t have to assume it’s a conscious effort to see how the platform could be discriminating in systematic ways.

On the one hand, YouTube and Google bill themselves as LGBTQ-friendly companies. Google is an official sponsor of the San Francisco Pride parade and has campaigned for gay rights around the world. “We’re proud that so many LGBTQ creators have chosen YouTube as a place to share their stories and build community,” YouTube spokesperson Alex Joseph said in a statement.

On the other hand, this is not the first time the LGBTQ community has felt betrayed by the company, and by YouTube in particular. There was an uproar in June when video journalist Carlos Maza, who is gay, accused the platform of siding with a right-wing provocateur who assailed Maza with homophobic slurs and spurred a harassment campaign against him. (After declining to ban Crowder or remove his videos, YouTube eventually opted to demonetize them.) So what’s going on here?

While the lawsuit portrays the discrimination as intentional on YouTube’s part, you don’t have to assume it’s a conscious effort to see how the platform could be discriminating in systematic ways. YouTube’s content policies and moderation processes are designed in such a way that it is bound to make unfair decisions every day, especially when it comes to topics or identities that are politically contested.

Every social media platform walks a line between permissiveness and moderation. Most aim for a semblance of political neutrality, lest they be accused of bias, while enforcing rules aimed at keeping users safe and their feeds nontoxic. The idea that goals like civility and safety can be entirely disentangled from politics has not fared well, however, in a time of rising white nationalism and social conflict. Companies such as Facebook and Twitter have struggled to strike the right balance, earning condemnation for their failure to rein in hate speech even as they face allegations of anti-conservative bias from Congressional Republicans and the president.

YouTube has an additional problem that stems from the nature of its advertising business. Its ads don’t just crop up at random places in users’ feeds, but are instead tied to specific videos. Because they’re video ads, they’re also costly to produce and to place compared to the display ads that are more common on other platforms. They have more in common with TV commercials than, say, a promoted tweet or Facebook post. All of which means that the financial success of Google’s YouTube division hinges on making sure advertisers feel comfortable with the user-created videos on which their ads are appearing. While Google doesn’t report YouTube’s earnings separately, the company cited pressure from advertisers to control YouTube’s content as a factor in its disappointing revenue growth earlier this year.

Unlike TV networks, however, YouTube doesn’t handpick all of its content, nor does it match ads to videos by hand. The content comes from users, and the matching is done via algorithm. That creates a high risk of ads being placed on videos that make for awkward or even offensive pairings, even if they don’t violate YouTube’s terms of service. In response to complaints from advertisers, YouTube over the years has significantly restricted the types of videos that are eligible for advertising, enforcing “advertiser-friendly content guidelines” that rule out broad swaths of content. These include violence, adult content, content relating to tobacco or firearms, and perhaps most vaguely, content pertaining to “controversial issues and sensitive events.” YouTube uses a combination of machine learning, user flagging, and an appeal process with human moderators to apply these guidelines.

From the standpoint of YouTube’s advertising business, that all makes sense, at least in theory. The company is leaving ad money on the table by ruling out tons of videos that would probably be just fine for many advertisers. After all, TV is full of sex, violence, and controversy. But YouTube has decided that it’s better off erring on what it considers the safe side, because if advertisers come to see it as a risky platform, they’ll just avoid it altogether. Indeed, advertisers boycotted the platform in 2017, and again this year.

From the standpoint of a social media platform, however, these guidelines are extremely constraining, not to mention nearly impossible to consistently enforce, especially with software. Advertising is not the only way to make money on YouTube videos: The company touts merchandising and paid channel memberships as alternatives. But advertising remains the dominant mode of monetization and the one that makes the most sense for most creators. The upshot is that, if you want to make money from ads on YouTube, you either have to steer far clear of content that anyone could consider sensitive, or brace yourself for a never-ending battle with the platform’s algorithms and human reviewers over exactly what content they consider “ad-friendly.”

It doesn’t help that “ad-friendly” is clearly a moving target. I wrote in July about the struggles of YouTube creators covering the Hong Kong protests. It was clear from their experiences with YouTube’s appeal process that even the company’s human moderators had varying interpretations of what constituted violence (police macing protesters?) or sensitive events (dissidents criticizing the Chinese Communist Party?). Several videos that were initially demonetized or hidden from search results were reinstated upon review. Others that had been rejected upon review were reinstated only after YouTube got press inquiries or Twitter complaints about them and took a second look.

It became clear in the course of my reporting that YouTube wasn’t intentionally doing the Chinese government’s bidding by suppressing coverage sympathetic to the protests. But it was effectively doing so unintentionally, by making such coverage detrimental to creators’ economic interests through demonetization and other forms of filtering. Even when human moderators reinstated content demonetized by the algorithms, the reversal came too late for that content to find a wide audience. And while the role of user flagging was unclear, it’s easy to imagine supporters of the Chinese government effectively gaming YouTube’s systems by reporting videos they didn’t like, thereby triggering the algorithm and forcing creators to go through the appeal process.

YouTube’s treatment of LGBTQ creators feels analogous, in some ways. Again, a marginalized group that some factions of society would like to silence is finding its videos unfairly flagged and punished by some combination of hostile users, ham-handed algorithms, and overmatched human reviewers, who are no doubt bringing their own biases to the job.

The possibility that at least some of those reviewers harbor blatantly homophobic attitudes is one that bears investigating. The lawsuit alleges that at least one human reviewer, identified as the head of a call center in South Asia, explained to the creators of GlitterBombTV’s channel GNews! that their channel had been restricted because of “the gay thing,” which he said contravened YouTube’s policies against “shocking” or “sexually explicit” content.

But it’s also worth investigating whether homophobia is embedded in the algorithms, content guidelines, and moderation systems themselves. The lawsuit suggests that videos are being flagged under the content guidelines merely for including words such as “lesbian,” “transgender,” or “queer.” It presents evidence that even videos that are wholly unrelated to sexuality have been demonetized or barred from being viewed in “restricted mode” because their creators identify as LGBTQ, appeal to an LGBTQ audience, or have other videos that deal with sexuality.

YouTube needs policies that specifically prohibit discriminatory enforcement, just as countries have laws protecting vulnerable groups.

YouTube denies this. “Our policies have no notion of sexual orientation or gender identity and our systems do not restrict or demonetize videos based on these factors or the inclusion of terms like ‘gay’ or ‘transgender,’” Joseph said in a statement.

But machine-learning algorithms don’t need to be explicitly trained to be homophobic in order to operate in a discriminatory manner. There are all kinds of ways that YouTube’s software might learn to treat LGBTQ creators and videos as suspect, the simplest being that homophobic users are repeatedly flagging it as such. There might also be advertisers who have made it known to YouTube that they’re uncomfortable running ads on content that deals with gender identity.

The issue is not that YouTube’s guidelines explicitly discriminate against LGTBQ creators. It’s that their vagueness and fundamental conservatism leave plenty of room for discriminatory enforcement, whether by human or machine. Marginalized groups in particular will always be disadvantaged by a system that relies partly on users to report what they find “sensitive” or “controversial.”

If YouTube wants to stop hurting LGBTQ creators, it isn’t enough to claim that its policies are agnostic toward gender identity or sexual orientation. It needs policies that specifically prohibit discriminatory enforcement, just as countries have laws protecting vulnerable groups. It needs to rethink the guidelines that treat controversy or sensitivity as reason in itself to demonetize a video. And it needs to implement strong processes to guard against bias at the level of the algorithm, the content reviewer, and maybe even the bigoted user.

A YouTube spokesperson said the company does test its systems for bias and train its reviewers on the nuances of the content policies, but declined to elaborate other than to say that no bias had been found. The company also noted that it recently updated its ad-friendly guidelines to include more specific examples.

Most of all, YouTube needs to stop pretending that its user platform can be a place for unfettered expression at the same time that its advertising platform is a sterile environment free of controversy. Claiming that demonetization isn’t a form of punishment is disingenuous. It’s fine to apply stricter standards and an extra layer of scrutiny to videos that YouTube monetizes or recommends. But if those standards include avoiding topics that affect marginalized groups, then YouTube itself becomes an engine of oppression.

OneZero

The frontlines of the future. A new Medium publication about tech and science.

Tip:

windows10 安装docker url 转义问题。

Docker error during connect: Get error during connect: Get

cd "C:\Program Files\Docker\Docker"
./DockerCli.exe -SwitchDaemon

在Powershell中,提升访问解决了我的问题。

Share:https://mp.weixin.qq/s/ZkFPYyD87ye5rdWE-4PgVA

JDK动态代理详解

后端技术精选 4月6日

 

作者:robin_yao

my.oschina/robinyao/blog/811193

本文主要介绍JDK动态代理的基本原理,让大家更深刻的理解JDK Proxy,知其然知其所以然。明白JDK动态代理真正的原理及其生成的过程,我们以后写JDK Proxy可以不用去查demo,就可以徒手写个完美的Proxy。

下面首先来个简单的Demo,后续的分析过程都依赖这个Demo去介绍,例子采用JDK1.8运行。

JDK Proxy HelloWorld

package com.yao.proxy;
/**
 * Created by robin
 */
public interface Helloworld {
    void sayHello();
}

 

package com.yao.proxy;
import com.yao.HelloWorld;
/**
 * Created by robin
 */
public class HelloworldImpl implements HelloWorld {
    public void sayHello() {
        System.out.print("hello world");
    }
}

 

package com.yao.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * Created by robin
 */
public class MyInvocationHandler implements InvocationHandler{
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target=target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method :"+ method.getName()+" is invoked!");
        return method.invoke(target,args);
    }
}

 

package com.yao.proxy;
import com.yao.HelloWorld;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;

/**
 * Created by robin
 */
public class JDKProxyTest {
    public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //这里有两种写法,我们采用略微复杂的一种写法,这样更有助于大家理解。
        Class<?> proxyClass= Proxy.getProxyClass(JDKProxyTest.class.getClassLoader(),HelloWorld.class);
        final Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
        final InvocationHandler ih = new MyInvocationHandler(new HelloworldImpl());
        HelloWorld helloWorld= (HelloWorld)cons.newInstance(ih);
        helloWorld.sayHello();

        //下面是更简单的一种写法,本质上和上面是一样的
        /* 
        HelloWorld helloWorld=(HelloWorld)Proxy.
                 newProxyInstance(JDKProxyTest.class.getClassLoader(),
                        new Class<?>[]{HelloWorld.class},
                        new MyInvocationHandler(new HelloworldImpl()));
        helloWorld.sayHello();
        */
    }

}

运行上面的代码,这样一个简单的JDK Proxy就实现了。

代理生成过程

我们之所以天天叫JDK动态代理,是因为这个代理class是由JDK在运行时动态帮我们生成。在解释代理生成过程前,我们先把-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true这个参数加入到JVM 启动参数中,它的作用是帮我们把JDK动态生成的proxy class 的字节码保存到硬盘中,帮助我们查看具体生成proxy的内容。我用的Intellij IDEA ,代理class生成后直接放在项目的根目录下的,以具体的包名为目录结构。

代理类生成的过程主要包括两部分:

  • 代理类字节码生成

  • 把字节码通过传入的类加载器加载到虚拟机中

Proxy类的getProxyClass方法入口:需要传入类加载器和interface

然后调用getProxyClass0方法,里面的注解解释很清楚,如果实现当前接口的代理类存在,直接从缓存中返回,如果不存在,则通过ProxyClassFactory来创建。

这里可以明显看到有对interface接口数量的限制,不能超过65535。其中proxyClassCache具体初始化信息如下:

proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

其中创建代理类的具体逻辑是通过ProxyClassFactory的apply方法来创建的。

ProxyClassFactory里的逻辑包括了包名的创建逻辑,调用ProxyGenerator. generateProxyClass生成代理类,把代理类字节码加载到JVM。

  • 包名生成逻辑默认是com.sun.proxy,如果被代理类是 non-public proxy interface,则用和被代理类接口一样的包名,类名默认是$Proxy 加上一个自增的整数值。

  • 包名类名准备好后,就是通过ProxyGenerator. generateProxyClass根据具体传入的接口创建代理字节码,-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 这个参数就是在该方法起到作用,如果为true则保存字节码到磁盘。代理类中,所有的代理方法逻辑都一样都是调用invocationHander的invoke方法,这个我们可以看后面具体代理反编译结果。

  • 把字节码通过传入的类加载器加载到JVM中: defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);

 

 private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
           //生成包名和类名逻辑
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class. 生成代理类的字节码
             * -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 在该部起作用
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //加载到JVM中
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

我们可以根据代理类的字节码进行反编译,可以得到如下结果,其中HelloWorld只有sayHello方法,但是代理类中有四个方法 包括了Object上的三个方法:equals,toString,hashCode。

代理的大概结构包括4部分:

  • 静态字段:被代理的接口所有方法都有一个对应的静态方法变量;

  • 静态块:主要是通过反射初始化静态方法变量;

  • 具体每个代理方法:逻辑都差不多就是 h.invoke,主要是调用我们定义好的invocatinoHandler逻辑,触发目标对象target上对应的方法;

  • 构造函数:从这里传入我们InvocationHandler逻辑;

 

package com.sun.proxy;

import com.yao.HelloWorld;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements HelloWorld {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void sayHello() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("com.yao.HelloWorld").getMethod("sayHello", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

常见问题:

  • toString() hashCode() equal()方法 调用逻辑:这个三个Object上的方法,如果被调用将和其他接口方法方法处理逻辑一样,都会经过invocationHandler逻辑,从上面的字节码结果就可以明显看出。其他Object上的方法将不会走代理处理逻辑,直接走Proxy继承的Object上方法逻辑。

  • interface 含有equals,toString hashCode方法时,和处理普通接口方法一样,都会走invocation handler逻辑,以目标对象重写的逻辑为准去触发方法逻辑;

  • interface含有重复的方法签名,以接口传入顺序为准,谁在前面就用谁的方法,代理类中只会保留一个,不会有重复的方法签名;

 

本文标签: 耗子ARTS